Fixing a Quirk of VB Lambda Expressions

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?

More by Author

Must Read