Saturday, December 17, 2011

Understanding Variable Scope in Anonymous Methods / Lambda Statements

There are 2 goals of this article. 1) to understand the variable scope in anonymous methods and 2) to look at a real world scenario where we have used the anonymous methods effectively.

Probably there will be several articles about this topic out there. Like:

To understand this article you should have:

  • Strong Knowledge of: Object Oriented Programming
  • Little bit know how of: Anonymous Methods / Lambda Statements

Description:

Note that in this article I've used term anonymous method which means both normal anonymous methods or lambda statements.

While working with JavaScript we use anonymous methods as delegates to function most of the time, for example:

document.getElementById('button1').onclick = function() {
    alert('button 1 clicked');
}

The thing which confused me a lot is the variable scoping. So let's try to learn this thing intuitively.

Let's start with a code for example:

public partial class Form1 : Form
    {
        public Form1()
        {
            InitializeComponent();
        }

        private void InitializeButton(string sValue)
        {
            string sToAdd = "****";
            this.button1.Click += (sender, e) =>
            {
                MessageBox.Show(sToAdd + sValue + sToAdd);
            };
        }

        private void Form1_Load(object sender, EventArgs e)
        {
            this.InitializeButton("Testing method");
        }
    }

I used to think that this anonymous method gets created somewhere in memory without being a part of any class. But then how this anonymous method is accessing the variables that are out of its scope like sValue and sToAdd in above example? This was the question which bothered me.

Later I tried to figure out if I don't have the anonymous method then how can I achieve this functionality i.e. how can we access the variables that are out of scope. Following solution came into my mind.

public partial class Form1 : Form
    {
        class tempclass
        {
            public string sValue;
            public string sToAdd;

            public void tempmethod1(object sender, EventArgs e)
            {
                MessageBox.Show(sToAdd + sValue + sToAdd);
            }
        }

        public Form1()
        {
            InitializeComponent();
        }

        private void InitializeButton(string sValue)
        {
            string sToAdd = "****";
            tempclass t = new tempclass();
            t.sValue = sValue;
            t.sToAdd = sToAdd;
            this.button1.Click += t.tempmethod1;
        }

        private void Form1_Load(object sender, EventArgs e)
        {
            this.InitializeButton("Testing method");
        }
    }

What I have done is just encapsulated the anonymous method and its variables in a temporary class. And guess what, compiler actually does the same thing when we use anonymous method and local variables.

Another workaround could be to move the method's local variables to class level for example:

    public partial class Form1 : Form
    {        
        public Form1()
        {
            InitializeComponent();
        }

        private string sToAdd;
        private string sValue;

        private void InitializeButton(string sValue)
        {
            this.sToAdd = "****";
            this.sValue = sValue;
            this.button1.Click += this.button1click;
        }

        private void button1click(object sender, EventArgs e)
        {
            MessageBox.Show(this.sToAdd + this.sValue + this.sToAdd);
        }

        private void Form1_Load(object sender, EventArgs e)
        {
            this.InitializeButton("Testing method");
        }
    }

Above example does the same thing, but we are actually extracting the inner variables of method to outer class which ultimately will make our class a mess and managing such type of classes is horribly hard.

As you can see the anonymous method makes our code simplified and easy to manage. We can easily encapsulate our method's local variables and we don't need to define them on class level.

A Real World Scenario:

The given example is NOT a real world scenario and does NOT actually show us the benefit of using anonymous method. So now I'll share a real world scenario which I face.

I was actually creating a TCP Communication Layer, which later can be used in network projects like if you are creating a chat server, multiplayer game, etc.

In short if you are creating a network application, you typically have a server which listens for incoming connections and also you have one or more clients which connect to server. When a connection is established between server and client, client then sends requests to server and server responds back for that particular request. Normally this communication between clients and server is carried out via events, which means whenever client/server receives data, an event is triggered that Data has been received.

    public class Server
    {
        private void PacketReceived(PacketClass pkt)
        {
            switch (pkt.Type)
            {
                case "Login":
                    if (isValidLogin(pkt))
                        SendPacket(new LoginSuccessPacket(pkt.PacketID));
                    else
                        SendPacket(new LoginFailedPacket(pkt.PacketID));
                    break;
            }
        }
        private void SendPacket(PacketClass pkt)
        {
            // code to send packet
        }
    }

    public class Client
    {
        // this login method just sends login packet to server and does NOT
        // return any login success or failure message because we can only
        // determine the success or failure once we received the response
        // packet back from server
        public void Login(string ID, string pwd)
        {
            SendPacket(new LoginPacket(ID, pwd));
        }

        private void PacketReceived(PacketClass pkt)
        {
            switch (pkt.Type)
            {
                case "LoginSuccessPaket":
                    // successfully logged in
                    break;
                case "LoginFailedPacket":
                    // failed
                    break;
            }
        }

        private void SendPacket(PacketClass pkt)
        {
            pkt.PacketID = GetNewPacketID();
            // code to send packet
        }
    }

Suppose we have above 2 classes. In both classes PacketReceived() is executed whenever some data is received and similarly SendPacket() method is used to send packet to other end.

Now we have used Client Class in our Client application (a Windows Forms Application) and have created a Login Form which uses that class to send Login Request to server.

Whenever we hit "Login" button Login() method gets called and login packet is sent to server. At this point the main UI thread sends bytes and immediately returns back. Now UI thread is free and you can again hit the Login button or can even close this window. We have to write some logic here to disable the Login button and to prevent the Form to be closed.

What I want is that my UI thread should freeze on the point where I have called the Login() method of Client class. It should either through the exception or should send me the success code. In simple words I want the thread to be blocked until

  • I don't receive a response from server either success or failure
  • Or Timeout occurs in case server didn't respond in time

This is because I don't want my login process to be spread across events. I just want my Login() method to be simple and concrete and it should return either the error or success.

Modified version of Client Class

Note that in order to understand this solution you should have a strong grip on Threading and Locking

    public class Client
    {
        private int GetNewPacketID()
        {
            // code to generate new unique Packet ID
        }

        // now login method is concrete and it will return either error or success
        public void Login(string ID, string pwd)
        {
            PacketClass pktReturned;
            // here thread will be blocked until the response from server is NOT received or timeout expired
            pktReturned = SendPacketGetResponse(new LoginPacket(ID, pwd), 10000); // 10000 milliseconds = 10 seconds
            // code to perform operation on pktReturned
        }

        // this is actually an event handler which is executed
        // if a packet is received from server
        private void PacketReceived(PacketClass pkt)
        {
            Action<PacketClass> callback = null;

            lock (this.CallBackMethods)
            {
                // trying to extract out the callback if is associated with this packet id
                if (this.CallBackMethods.TryGetValue(pkt.PacketID, out callback))
                    // if found then we will remove it from dictionary
                    this.CallBackMethods.Remove(pkt.PacketID);
            }

            // if this is the response of some packet
            if (callback != null)
            {
                // call the callback
                callback(pkt);
            }
            else
            {
                // handle packet normally
            }
        }

        // this dictionary will hold the callback methods associated
        // with packet id. this dictionary will only be used
        // if we want to call our custom delegate on arrival of certain
        // packet id
        private Dictionary<int, Action<PacketClass>> CallBackMethods = new Dictionary<int, Action<PacketClass>>();

        // sends packet to server and does NOT wait for server response
        // immediately returns to the caller
        private void SendPacket(PacketClass pkt, Action<PacketClass> callback)
        {
            // attach a new unique packet id with the given packet
            pkt.PacketID = GetNewPacketID();

            // if callback method is provided then it means we want
            // to execute our callback method whenever response of
            // the given packet is received
            if (callback != null)
            {
                // add in the dictionary
                lock (this.CallBackMethods)
                {
                    this.CallBackMethods.Add(pkt.PacketID, callback);
                }
            }
            
            // code to send packet
        }

        // this method will block the calling thread until
        // 1) response is received from server
        // 2) or timeout expired
        private PacketClass SendPacketGetResponse(PacketClass pktToSend, int iTimeOut)
        {
            PacketClass pktReturn = null;

            using (System.Threading.AutoResetEvent are = new System.Threading.AutoResetEvent(false))
            {
                // send packet to server
                this.SendPacket(pktToSend, (pktReceived) =>
                    // anonymous method:
                {
                    // pktReturn variable has been declared in the outer method i.e.
                    // SendPacketGetResponse
                    pktReturn = pktReceived;
                    are.Set();  // Release the sendpacketgetresponse() method thread
                });

                // here the calling thread will be blocked
                // and once the response packet is received in our PacketReceived() method
                // it will call our anonymous method (written above) and our anonymous
                // method will call are.Set() which will resume this thread
                if (!are.WaitOne(iTimeOut))
                {
                    // since timeout has been expired therefore
                    // we are now removing the callback method from our dictionary
                    // even if server sends a response we are NOT interested 
                    lock (this.CallBackMethods)
                    {
                        this.CallBackMethods.Remove(pkt.PacketID);
                    }
                    throw new Exception("Timeout Expired");
                }
            }
            return pktReturn;
        }
    }

The core of this topic is the SendPacketGetResponse() method in above example.

The main goal which I've achieved here is that I have performed asynchronous operation synchronously. Plus the the returning variable is declared within the SendPacketGetResponse() method while the actual packet is received in PacketReceived() method but using Anonymous Method we encapsulated our whole process in a single method.

No comments: