Understanding Lambdas and Delegates.-VBForums
Results 1 to 6 of 6

Thread: Understanding Lambdas and Delegates.

  1. #1

    Thread Starter
    Angel of Code Niya's Avatar
    Join Date
    Nov 2011
    Posts
    4,998

    Understanding Lambdas and Delegates.

    If you spent any amount of time perusing the VB.Net section of these forums, you are sure to eventually come across cryptic looking code snippets that look like:-
    vbnet Code:
    1. '
    2. If Array.TrueForAll(accountNumbers, Function(accountNumber) Regex.IsMatch(accountNumber, "regex pattern here")) Then
    3.     MessageBox.Show("All account numbers are valid.")
    4. End If
    The above is code snippet posted by jmcilhinney and you would usually see posts like that in threads where members ask questions that involve lists, arrays, searches or LINQ.

    For the purpose of this piece we are going to focus on a particular part of that piece of code, mainly:-
    vbnet Code:
    1. TrueForAll(accountNumbers, Function(accountNumber) Regex.IsMatch(accountNumber, "regex pattern here"))

    Recently, I've had a user ask me about the Function keyword embedded in a statement similar to jmc's one:-
    vbnet Code:
    1. strTest = objFile.ReadToEnd.Trim.Replace(vbCr, "").Split(vbLf).Distinct.OrderBy(Function(s) s).ToArray
    He asked me to explain Function(s) s. Looking at it, I realized that it really does look confusing and given the amount of times people suggest similar constructs to users asking questions, its a fair bet that there are a lot of VB beginners who read such code and feel like thy're are reading Chinese. I often get the feeling that a lot users who receive such code as a solution to their problem simply accept that it works but don't really understand what is going on or what it means. If you are one such person then please continue reading. In this thread, I'll make an attempt to bring light to the darkness surrounding these types of expressions.

    Lets Begin

    vbnet Code:
    1. '
    2.         Dim lstNames As New List(Of String)
    3.         Dim lstFound As List(Of String)
    4.  
    5.         lstNames.Add("John Henry")
    6.         lstNames.Add("Jim Williams")
    7.         lstNames.Add("Mack Pierce")
    8.         lstNames.Add("John Halter")
    9.  
    10.         lstFound = lstNames.FindAll(Function(s) s.StartsWith("john", StringComparison.OrdinalIgnoreCase))
    The above code creates a list of names and searches these list of names for all names that begin with john ignoring case. The most cryptic line in the above code snippet is the search itself:-
    vbnet Code:
    1. lstFound = lstNames.FindAll(Function(s) s.StartsWith("john", StringComparison.OrdinalIgnoreCase))
    For the purposes of this article we are going to assume that you do not understand this line of code at all or at least very little of it. When I make any attempt to explain or to teach, I usually like to begin with something that everybody understands and slowly build on this, adding bit by bit, the missing pieces of knowledge. This is the style I'm going to use with this article. Experienced programmers may find it tedious but please note that I'm targeting beginners so I may at times severely dumb things down but hopefully not too much. Now lets continue with a most basic unit of programming. The function:

    Functions

    Every programmer should know what a function is. In VB.Net and other object oriented languages they are sometimes referred to as methods but for the purposes of this article we are going to treat methods, functions and subs as synonymous terms.
    vbnet Code:
    1. '
    2.     Private Sub ShowMessage(ByVal msg As String)
    3.         MessageBox.Show(msg)
    4.     End Sub
    The above is a sub, a function that returns no value. It takes one parameter and performs an action based on the value of this parameter. While there isn't much more that can be said of functions than that, there is one very important abstract quality about functions that you must be aware of in order to understand what I'm going to show you. This function and every other has a signature.

    Function signatures

    A function's signature is determined by 4 things.
    • The number of parameters
    • The type of the parameters
    • The order of the parameters
    • The function's return type

    Please note that the name of the function and the names of the parameters are completely irrelevant, only the 4 properties listed above matter. If those 4 qualities of two different functions are identical then the functions are said to have the same signature.

    Delegates

    Believe it or not, at runtime every function has an address in memory. Every time you call a function, the runtime must look up the address in memory to jump to so the function can be executed. Now that's an oversimplification but its not necessary to delve to deeply into the details of this for the purpose of this article.

    In languages like C++, one is able to obtain addresses to functions and store them is what is called a function pointer. Delegates in VB.Net are based on this idea. In fact the MSDN library describes a delegate as a type safe function pointer. You can store the address of a function in a delegate variable. For a delegate type variable to be able to store the address of a function, it must have an identical signature to the function, so taking the example sub above, ShowMessage, we can define a delegate for it like this:-
    vbnet Code:
    1. Private Delegate Sub ShowMessageDelegate(ByVal strn As String)
    Notice that its parameter is named differently from the function's parameter but it will still work because as I said, the name of the parameter is not relevant, only its type.

    You can now declare a variable of this delegate type like:-
    vbnet Code:
    1. Dim addrShowMsg As ShowMessageDelegate
    And you and retrieve the address of the actual function and store it in this variable like this, using the AddressOf operator:-
    vbnet Code:
    1. addrShowMsg = AddressOf ShowMessage
    If you want, you can combine declaration and assignment like:-
    vbnet Code:
    1. Dim addrShowMsg As New ShowMessageDelegate(AddressOf ShowMessage)
    The AddressOf operator creates an instance of a delegate. I.e. It actually refers to a specific function now. Delegate variables can be thought of in much the same way as a class variable. It can refer to an instance or Nothing just like any other class variable:-
    vbnet Code:
    1. addrShowMsg = Nothing

    Ok, so why did MS in their wisdom decide to introduce this concept of delegates into VB.Net ? Well for one thing, it underpins the operation of events in the .Net framework but it also introduces a certain flexibility to the language. I said above that you can think of delegate variables in much the same way as any class variable so it must also mean that we can pass delegates into function arguments the same as you can pass any class. How can this be of benefit ? Ok think of this:-
    vbnet Code:
    1. '
    2.     Private Function AddNumbers(ByVal num1 As Integer, ByVal num2 As Integer) As Integer
    3.         Return num1 + num2
    4.     End Function
    5.  
    6.     Private Function SubtractNumbers(ByVal num1 As Integer, ByVal num2 As Integer) As Integer
    7.         Return num1 - num2
    8.     End Function
    The above are two functions, one adds two numbers and the other subtracts them. Notice any thing about these two functions ? Look closely now. You should recognise that they have identical signatures. They both take two Integer parameters and return an Integer. Remember, ignore the fact that their parameters are named the same, the name of the function and its parameters don't matter.

    The fact that their signatures are identical make it possible for you to define a single delegate type that can hold an instance of either function:-
    vbnet Code:
    1. Private Delegate Function MathOperation(ByVal operand1 As Integer, ByVal operand2 As Integer) As Integer

    As MathOperation is a type, it becomes possible to define a function like:-
    vbnet Code:
    1. '
    2.     Private Function DoOperation(ByVal mathOp As MathOperation, ByVal op1 As Integer, ByVal op2 As Integer) As Integer
    3.         Return mathOp(op1, op2)
    4.     End Function
    The above function takes a delegate instance and two Integers and executes the delegate using the two Integers as parameters for the delegate instance.

    You can use that function to perform either math operation like:-
    vbnet Code:
    1. Dim ans As Integer = DoOperation(AddressOf AddNumbers, 10, 5)
    The above would perform an addition because the AddressOf operator passes the address of the AddNumbers function in an instance of the MathOperation delegate to the DoOperation function.

    You should notice by now that there is a certain resemblance between the above code and the search code I started with at the top of this article:-
    vbnet Code:
    1. lstFound = lstNames.FindAll(Function(s) s.StartsWith("john", StringComparison.OrdinalIgnoreCase))

    The above code embodies the same idea of passing delegate instances into functions except that the above uses what is called a lambda, something we will explore in subsequent posts.

    To be continued...
    Last edited by Niya; May 8th, 2012 at 08:03 AM. Reason: Minor edit
    Treeview with NodeAdded/NodesRemoved events | BlinkLabel control | Calculate Permutations | Object Enums | ComboBox with centered items | .Net Internals article(not mine) | Wizard Control | Understanding Multi-Threading | Simple file compression | Demon Arena


    C++ programmers will dismiss you as a cretinous simpleton for your inability to keep track of pointers chained 6 levels deep and Java programmers will pillory you for buying into the evils of Microsoft. Meanwhile C# programmers will get paid just a little bit more than you for writing exactly the same code and VB6 programmers will continue to whitter on about "footprints". - FunkyDexter

    There's just no reason to use garbage like InputBox. -jmcilhinney

  2. #2

    Thread Starter
    Angel of Code Niya's Avatar
    Join Date
    Nov 2011
    Posts
    4,998

    Re: Understanding Lambdas and Delegates.

    Lambdas

    The term lambda has its roots in mathematics but in .Net world it can simply be thought of as an anonymous inline function. Why is it anonymous ? Because its a function that has no name. How can such a function be used ? Well remember that the .Net framework has support for delegates and delegates are only concerned with signatures not function names and parameter names. Remember the above MathOperation delegate type in the OP ? I used the AddressOf operator to pass the address of the AddNumbers function in an instance of the MathOperation delegate to DoOperation. Using a lambda, one can also do this:-
    vbnet Code:
    1. Dim ans As Integer = DoOperation(Function(op1, op2) op1 + op2, 10, 5)
    There you see that cryptic Function keyword again. Let us now attempt to decrypt this.

    The Function keyword creates an instance of a delegate just like the AddressOf operator but instead of referring to an already existing function, it allows you to define what this function does. However please be aware that it is severely limited in comparison to real functions:-
    vbnet Code:
    1. '
    2.         Dim AddOp As MathOperation
    3.  
    4.         AddOp = Function(op1 As Integer, op2 As Integer) op1 + op2
    The above uses the MathOperation delegate type defined in the OP to declare a variable. We then supply an instance of a delegate of an anonymous function that matches the signature of the delegate type, which is two Integer parameters and an Integer return type. Notice that when declaring anonymous functions that we cannot declare its return type. Its return type is inferred from the delegate. Remember that the delegate is defined:-
    vbnet Code:
    1. Private Delegate Function MathOperation(ByVal operand1 As Integer, ByVal operand2 As Integer) As Integer
    The return type of the delegate is Integer and since the result instance of the Function keyword is assigned to a variable declared as this type of delegate, then the compiler can infer Integer as the return type. This type inference also applies to parameter types, therefore we can omit the types in the function declaration:-
    vbnet Code:
    1. AddOp = Function(op1, op2) op1 + op2

    This way of delaring functions has a severe limitation. You can only use a single statement as far as I know and this statement MUST return a value. op1 + op2 is a binary operation that returns a value. It could also be another function call or a boolean evaluation like those you use in a If...Then statement. These statements return values. So the above function executes op1 + op2 and returns the result of that operation. Think of :-
    vbnet Code:
    1. Function(op1, op2) op1 + op2
    as being equivalent to:-
    vbnet Code:
    1. '
    2.     Private Function AddNum(ByVal op1, ByVal op2)
    3.         Return op1 + op2
    4.     End Function

    If I did this article well then:-
    vbnet Code:
    1. lstFound = lstNames.FindAll(Function(s) s.StartsWith("john", StringComparison.OrdinalIgnoreCase))
    Should not seem so cryptic any more. It should become obvious that the FindAll method of the List(Of T) class takes a delegate instance which it uses to execute its search. So lets explore this now.

    Decrypting FindAll

    Lets start with the delegate instance being passed to FindAll:-
    vbnet Code:
    1. Function(s) s.StartsWith("john", StringComparison.OrdinalIgnoreCase)

    Its a delegate instance of a function that takes a single parameter, but what is its parameter type and its return type ? In other words, how is its delegate class defined ? The delegate type is called Predicate(Of T), which is defined somewhere in the .Net framework. This is a generic delegate, something I have not covered but it can be fit into the framework of what I've already discussed if you think of it in my search example as being defined as:-
    vbnet Code:
    1. Public Delegate Function Predicate(ByVal obj As String) As Boolean
    A function that takes a String and returns a Boolean. In my example, I create a list of names. Each name is of the String data type. FindAll enumerates the list of these Strings, invoking the delegate on each one passing the String through the parameter of the anonymous function. We are expected to evaluate that String inside the function and return either True or False. Everytime we return True, FindAll adds the String to another list which becomes the list of all matches. The function's body in my example consist of this statement:-
    vbnet Code:
    1. s.StartsWith("john", StringComparison.OrdinalIgnoreCase)
    Its a call to the StartsWith method of the String class which returns True if a particular String starts with a certain combination of characters. Its second parameter in this example tells it to ignore case. FindAll calls this of every String in the list in order to find all the strings that begin with the letters john.

    If I wanted FindAll to return all Strings in the list that say....have a length of 11 characters, Id do this:-
    vbnet Code:
    1. lstFound = lstNames.FindAll(Function(s) s.Length = 11)
    The statement:-
    vbnet Code:
    1. s.Length = 11
    evaluates to True when a String contains 11 characters. Its the type of thing you see in an If...Then statement.

    In the next post, I hope to try and explain the concept behind generic delegates, the way most methods like FindAll in the .Net framework are declared to accept as parameters but at least up to this point you should have a solid understanding of delegates and lambdas such that you would no longer find methods like FindAll and OrderBy so intimidating. Look out for my post on generic delegates at a later date folks. Good luck and good night
    Last edited by Niya; May 8th, 2012 at 08:06 AM. Reason: Minor edit.
    Treeview with NodeAdded/NodesRemoved events | BlinkLabel control | Calculate Permutations | Object Enums | ComboBox with centered items | .Net Internals article(not mine) | Wizard Control | Understanding Multi-Threading | Simple file compression | Demon Arena


    C++ programmers will dismiss you as a cretinous simpleton for your inability to keep track of pointers chained 6 levels deep and Java programmers will pillory you for buying into the evils of Microsoft. Meanwhile C# programmers will get paid just a little bit more than you for writing exactly the same code and VB6 programmers will continue to whitter on about "footprints". - FunkyDexter

    There's just no reason to use garbage like InputBox. -jmcilhinney

  3. #3

    Thread Starter
    Angel of Code Niya's Avatar
    Join Date
    Nov 2011
    Posts
    4,998

    Re: Understanding Lambdas and Delegates.

    Reserved Post 2.........
    Treeview with NodeAdded/NodesRemoved events | BlinkLabel control | Calculate Permutations | Object Enums | ComboBox with centered items | .Net Internals article(not mine) | Wizard Control | Understanding Multi-Threading | Simple file compression | Demon Arena


    C++ programmers will dismiss you as a cretinous simpleton for your inability to keep track of pointers chained 6 levels deep and Java programmers will pillory you for buying into the evils of Microsoft. Meanwhile C# programmers will get paid just a little bit more than you for writing exactly the same code and VB6 programmers will continue to whitter on about "footprints". - FunkyDexter

    There's just no reason to use garbage like InputBox. -jmcilhinney

  4. #4
    Frenzied Member make me rain's Avatar
    Join Date
    Sep 2008
    Location
    india/Hubli
    Posts
    1,920

    Re: Understanding Lambdas and Delegates.

    Oh what a great piece of article ,
    i was in need of this, it is simple & understandable ,
    we expect some more articles like these in future on the forum
    The averted nuclear war
    My notes:

    PrOtect your PC. MSDN Functions .OOP LINUX forum
    .LINQ LINQ videous
    If some one helps you please rate them with out fail , forum doesn't expects any thing other than this

  5. #5

    Thread Starter
    Angel of Code Niya's Avatar
    Join Date
    Nov 2011
    Posts
    4,998

    Re: Understanding Lambdas and Delegates.

    Thank you You will see more in the future.
    Treeview with NodeAdded/NodesRemoved events | BlinkLabel control | Calculate Permutations | Object Enums | ComboBox with centered items | .Net Internals article(not mine) | Wizard Control | Understanding Multi-Threading | Simple file compression | Demon Arena


    C++ programmers will dismiss you as a cretinous simpleton for your inability to keep track of pointers chained 6 levels deep and Java programmers will pillory you for buying into the evils of Microsoft. Meanwhile C# programmers will get paid just a little bit more than you for writing exactly the same code and VB6 programmers will continue to whitter on about "footprints". - FunkyDexter

    There's just no reason to use garbage like InputBox. -jmcilhinney

  6. #6
    Junior Member
    Join Date
    Jul 2013
    Posts
    16

    Re: Understanding Lambdas and Delegates.

    Isn't there a point where you just accept that Abracadabra opens a door, even though you don't understand how?

    Seriously though, I am really glad to see this, and it will help me in the future, Thank you

Posting Permissions

  • You may not post new threads
  • You may not post replies
  • You may not post attachments
  • You may not edit your posts
  •  



Featured


Click Here to Expand Forum to Full Width

Survey posted by VBForums.