Generic Delegates and Lambda Expressions

Introduction

Archimedes said: "Give me a place to stand and a lever long enough and I will move the world." Archimedes was referring to the potential power of tools to magnify the amount of work that can be done. Generic delegates and Lambda Expressions are tools. These tools magnify the amount of work you can do with less code.

In this article, you will explore generic delegates, the ForEach(Of T) generic method, and Lambda Expressions for VB9. Besides the ForEach(Of T) method, you'll look at the Action, Func, and Predicate anonymous delegates.

A Quick Review of Lambda Expressions

When you hear someone talk about functional programming, they are referring to Lambda Expressions. Lambda Expressions have been in other languages for a while and they are based on 70 year old mathematics, Lambda Expressions.

For your purposes, Lambda Expressions are basically inline functions that are used where historically you would have used delegates. You use Lambda Expressions instead because of their concise nature they fit in more naturally with LINQ and other new .NET technologies. A Lambda Expression is comprised of the keyword Function, a parameter list, and is immediately followed by the statement or expression that makes up the body of the function.

In VB9, Lambda Expressions begin with Function and have n-number of arguments. If the types can be inferred, the argument need not be provided explicitly. If the type cannot be inferred or Option Strict On is set, the type (As Type) must be provided for the arguments. Immediately following the Function(arg1, arg2, ..., argn) part of the expression, you need to supply the expression. The expression must return a result. You'll see some Lambda Expressions in the code samples.

The generic delegate Action(Of T) is a rough implementation of the Command behavior pattern. To use Action(Of T), declare a variable of type Action(Of T) and specify the type for T; for example, Integer. Then, initialize the Action object with the address of a delegate that accepts the number and type of arguments expressed in the Action declaration. (You can provide more than one argument for Action.) Listing 1 demonstrates how to use Action with a single argument.

Listing 1: Declaring and initializing an instance of Action(Of T) where T is expressed as an Integer and it is assigned to the address of a subroutine, Print.

Sub DemoActionOfT()
   ' Can't use Lambda here (can in C#) because VB Lambdas
   ' have a return value
   Dim Action As Action(Of String) = AddressOf Print
   Action("Hello World")
   Console.ReadLine()
End Sub

Sub Print(ByVal str As String)
   Console.WriteLine(str)
End Sub

In VB9, you can't initialize an Action object with a Lambda Expression because Lambda Expressions in VB9 are designed around expressions—code that has a return value—not statements—or, lines of code that yield no return value.

Easy Iteration with Array.ForEach(Of T)

ForEach(Of T) performs a specified action over an array of items where T indicates the type of the item. The first argument to ForEach is the array and the second arguments is the delegate of an instance of Action(Of T). Listing 2 demonstrates how to use ForEach. The array is represented by the anonymous type declaration of numbers and the Action(Of T) object is represented by the AddressOf Print.

Listing 2: Demonstrates the ForEach generic method that iterates over an array of items and performs the operation expressed by the Action delegate.

Sub DemoForEach()
   Dim numbers() = {1, 2, 3, 4, 5}

   Array.ForEach(numbers, AddressOf Print)
   Console.ReadLine()

End Sub

Sub Print(ByVal str As String)
   Console.WriteLine(str)
End Sub

Capturing Behaviors with Func(Of T)

The generic delegate Func(Of T) is designed to accept n-arguments—parameterized types—and the nth (or last argument) is the return type. For example, Func(Of Integer, Integer, Integer) means that the generic delegate accepts three integers and returns an integer. Because Func has a return argument, it can be initialized with a Lambda Expression. Listing 3 demonstrates a Lambda Expression that is assigned to an instance of Func(Of Integer, Integer, Integer) where the behavior performs simple arithmetic.

Listing 3: A Lambda Expression that accepts to arguments assigned to an instance of Func(Of T, T, T).

Sub DemoFunctionOfT()

   ' Argument 1, 2, n and result, the last argument
   Dim Adder As Func(Of Integer, Integer, Integer) = _
   Function(x, y) x + y

   Console.WriteLine(Adder(4, 5))
   Console.ReadLine()
End Sub

Implementing Comparison Behaviors with Predicate(Of T)

The Predicate delegate is designed to accept arguments and return a Boolean. Its intended use is to accept test parameters and return a Boolean indicating the Boolean result of the test. In the example in Listing 4, the code tests the length of the input string to determine whether it is five characters in length.

Listing 4: The Predicate generic delegate demonstrates how to capture a test with a Boolean result.

Sub DemoPredicateOfT()
   ' Can use Lambda because predicate has return of Boolean
   Dim pred As Predicate(Of String) = _
   Function(str) str.Length = 5

   Console.WriteLine("'Hello' is five characters long is {0}", _
      pred("hello"))
   Console.ReadLine()
End Sub

Although you aren't required to assign Lambda Expressions to generic delegates, sometimes using the generic delegates make the code clearer and generic delegates are a convenient means of reusing lambda Expressions (or delegates, as is the case with Action) or even passing them around to functions.

Summary

Lambda Expressions in VB9 start with the Function keyword and parameters. The body of the Lambda Expression (in VB9) is an expression, aka code that yields a result. Lambda Expressions can be used directly or assigned to the generic delegates like Predicate and Func. Having these convenient storage types for Lambda Expressions makes it easier to reuse Lambda Expressions and pass them as arguments.

Remember that Lambda Expressions are basically shorthand for delegates. You can use Lambda Expressions anywhere you would use a regular delegate. The key benefit is that Lambda Expressions are more concise and consequently fit nicely with new code added to the .NET framework to support LINQ (Language Integrated Query).

About the Author

Paul Kimmel is the VB Today columnist for www.codeguru.com and has written several books on object-oriented programming and .NET. Check out his upcoming book LINQ Unleashed for C# due in Spring 2008. You may contact him for technology questions at pkimmel@softconcepts.com.

If you are interested in joining or sponsoring a .NET Users Group, check out www.glugnet.org. Glugnet opened a users group branch in Flint, Michigan in August 2007. If you are interested in attending, check out the www.glugnet.org web site for updates.

Copyright © 2007 by Paul T. Kimmel. All Rights Reserved.



Comments

  • There are no comments yet. Be the first to comment!

Leave a Comment
  • Your email address will not be published. All fields are required.

Top White Papers and Webcasts

  • Today's agile organizations pose operations teams with a tremendous challenge: to deploy new releases to production immediately after development and testing is completed. To ensure that applications are deployed successfully, an automatic and transparent process is required. We refer to this process as Zero Touch Deployment™. This white paper reviews two approaches to Zero Touch Deployment--a script-based solution and a release automation platform. The article discusses how each can solve the key …

  • On-demand Event Event Date: December 18, 2014 The Internet of Things (IoT) incorporates physical devices into business processes using predictive analytics. While it relies heavily on existing Internet technologies, it differs by including physical devices, specialized protocols, physical analytics, and a unique partner network. To capture the real business value of IoT, the industry must move beyond customized projects to general patterns and platforms. Check out this webcast and join industry experts as …

Most Popular Programming Stories

More for Developers

RSS Feeds