Results 1 to 7 of 7

Thread: Understanding Lambdas and Delegates.

Threaded View

  1. #1

    Thread Starter
    Angel of Code Niya's Avatar
    Join Date
    Nov 2011
    Posts
    8,598

    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

    Copy/move files using Windows Shell | I'm not wanted

    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

    The threads I start are Niya and Olaf free zones. No arguing about the benefits of VB6 over .NET here please. Happiness must reign. - yereverluvinuncleber

Posting Permissions

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



Click Here to Expand Forum to Full Width