October 20, 2014
Hot Topics:
RSS RSS feed Download our iPhone app

Fixing a Quirk of VB Lambda Expressions

  • February 21, 2008
  • By Paul Kimmel
  • Send Email »
  • More Articles »

Introduction

A lot of very smart and friendly people from Microsoft help me. For this reason, I try not to be critical and limit criticism to constructive criticism. This doesn't mean everything that comes out of Redmond is perfect, but much of it is exceptional.

That said, VB Lambda Expressions bug me.

Apparently, a lot of VB programmers complain about the "new" VB not being like the old VB, so choices are made to appeal to this audience (although I am not exactly sure who these folks are.) One such choice was to make VB Lambda Expressions more verbose than C# Lambda Expressions. C# uses n => behavior. VB uses Function(n) behavior. Herein lays the problem. In VB, a Function expects a return value and C# Lambda Expressions do not. The result is that it's a compiler error to define a Lambda Expression without a return value in VB. For example,

Function(s) Console.WriteLine(s)

generates a compiler error, but

s => Console.WriteLine(s)

in C# does not. In addition, because C# supports {} for the function body it is possible for a Lambda Expression to be a compound statement. VB9 does not support compound statements in Lambda Expressions.

In this article, I will demonstrate a workaround for non-value returning Lambda Expressions and an imperfect resolution to compound statements, albeit an in perfect resolution.

Writing a Simple Lambda Expression

If you have forgotten or didn't know, Lambda Expressions are based on a seventy-year-old mathematical invention that permits a shorthand notation. In VB, they are an evolution of the very short hand notation for delegates and anonymous delegates (that we skipped over in VB. Another peeve of mine, but, oh well.)

Lambda Expressions are basically the Function keyword, an argument list with no modifiers or data types, and a statement—the method body. They are a trimmed down Function. For example,

Function(n) n + 1

is a Lambda Expressions that accepts an argument n and returns n + 1. You might call this an increment function. Listing 1 contains a really simple sample program that declares an array of integers and sends all of the integers to the console one at a time.

Listing 1: Iterating over an array of integers—very simple.

Module Module1

   Sub Main()

      Dim numbers = New Integer() {1, 2, 3, 4, 5, 6}

      Dim num As Integer

      For Each num In numbers
         Console.WriteLine(num)
      Next

      Console.ReadLine()

   End Sub

End Module

Ostensibly, you should be able to use the Array.ForEach(Of T) generic method and the Action(Of T) generic delegate and tighten up the loop code with a single statement and a Lambda Expression, as shown in Listing 2.

Listing 2: Tightening up the loop with Array.ForEach(Of T) and a Lambda Expression.

Module Module1

   Sub Main()

      Dim numbers = New Integer() {1, 2, 3, 4, 5, 6}

Array.ForEach(numbers, Function(n) Console.WriteLine(n)) Console.ReadLine() End Sub End Module

Unfortunately, this code produces the compiler error BC30491; the expression does not produce a value. The reason is that "Function" is designed to expect a return value and Console.WriteLine has no return value. In short, the second parameter of Array.ForEach expects an instance of Action(Of T), which is defined as a subroutine delegate. (By the way, the code works fine in C# because all methods are functions. It just so happens that void functions are roughly equivalent to VB9 Sub routines, but in C# it is a function all the same.) What to do?

Fixing the Function-Lambda Problem

The net result is that Action(Of T) is used in a lot of places, but you can't use Lambda Expressions (easily) in VB9 to satisfy these arguments. You can in C#.

To resolve the problem, you can write a wrapper for Console.WriteLine that accepts the parameter you want to write and define the wrapper as a Function, returning Nothing for the wrapper. The result is you now can use the Lambda Expression in the Array.ForEach, this time calling the wrapper method. Listing 3 fixes your small problem.

Listing 3: You can fix the requirement that Lambda Expressions in VB9 have a return value by defining a wrapper method that returns "Nothing".

Module Module1

   Sub Main()

      Dim numbers = New Integer() {1, 2, 3, 4, 5, 6}


      Array.ForEach(numbers, Function(n) WriteLine(n))
      Console.ReadLine()

   End Sub

   Function WriteLine(ByVal obj As Object)
      Console.WriteLine(obj)
      Return Nothing

   End Function

End Module

If you notice, the wrapper method also fixes the second problem in thr introduction too (although a bit kludgy) by permitting yoy to have compound statements for all intents and purposes in your Lambda Expression.

Summary

Lambda Expressions using the keyword Function in VB9 must return a value and can't be compound statements. Lambda Expressions must return values in VB9 because that's what the compiler expects Functions to do. Lambda Expressions in VB9 can't be compound because there is nowhere to put the End Function piece.

In C#, Lambdas can be compound with the {} and they can return a value but they don't have to. This means that Lambda Expressions in VB9 are weaker and less capable than they are in C#.

Although the sample in this article demonstrates a fix, maybe what Microsoft should do is introduce a new keyword Lambda that has function and subroutine semantics and permit multiple statements. If not, VB9 Lambda Expressions are less flexible in VB9 and implementing the workaround makes VB9 Lambda Expressions the poor cousin.

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 July 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 © 2008 by Paul T. Kimmel. All Rights Reserved.






Comment and Contribute

 


(Maximum characters: 1200). You have characters left.

 

 


Sitemap | Contact Us

Rocket Fuel