Lambda expressions, Part I: Syntax

As I alluded to in my earlier entry, one of the features we’re working on for LINQ/Orcas is lambda expressions. Now, I might be tempted to say “You know, we should really call them ‘inline functions’ instead of ‘lambda expressions,’ because I think ‘inline function’ is a little clearer and less of a computer science-y term.” but you can rest assured that I learned my lesson. Lambda expressions they are. (Do you detect a trace of bitter sarcasm there? Perhaps just a little.)

For those not well versed in the arcana of the lambda calculus, a lambda expression is, uh, basically an inline function. Take this case, where you’ve got a function that takes another function and applies it to an array:

    Delegate Function TransformDelegate(input As Integer) As Integer

    Sub ApplyTransform(array() As Integer, transform As TransformDelegate)
        For i As Integer = 0 To array.Length - 1
            array(i) = transform(array(i))
    End Sub

Now, normally you’d have to create a whole function just to be able to use it:

    Function AddOne(x As Integer) As Integer
        Return x + 1
    End Function

    Sub Main()
        Dim a() As Integer = {1, 2, 3}
        ApplyTransform(a, AddressOf AddOne)
    End Sub

But this is kind of silly, right? What you’d really like to do is create an inline function that you could immediately pass to something that took a delegate. Then you could just express right there in the code what you want to do. Something like:

    Sub Main()
        Dim a() As Integer = {1, 2, 3}
        ApplyTransform(a, Function(x) x + 1)
    End Sub

This is all a lambda expression is, really, just an inline function that you can pass to something that takes a delegate type. However, lambda expressions can be quite powerful and form one of the major underpinnings of LINQ. For example, you’ll notice that the LINQ Where function takes a delegate type. So instead of using the higher level From … Where syntax, you could also write things like:

    Dim ys = xs.Where(Function(x) x < 5)

This calls the “Where” function on “xs,” passing in the inline function “x < 5″. The Where function then just applies that inline function to the elements of the collection to determine what to filter in or out of the collection. (You’ll notice I omitted all the types from the inline function; lambda expressions use type inference so that you don’t have to give all the types, but that’s a whole other blog entry.)

One of the major things we’re still finalizing, though, is the exact syntax of lambda expressions in VB (because, of course, the syntax is always the hardest thing to get right). C# is using a “fat arrow, no introducing token” syntax that looks something like this:

    var ys = xs.Where(x => x < 5)

This is certainly one possibility. It has both the advantage of being extremely concise and the disadvantage of being extremely concise. So it’s quick to use but kind of cryptic. Consistency between the languages is nice, but another possibility is the one I used in my initial examples:

    Dim ys = xs.Where(Function(x) x < 5)

This is more wordy and less concise than the “fat arrow, no introducing token” format, but it’s got the advantage that it’s consistent with the rest of the VB language and makes it really obvious what you’re doing (i.e. creating a function). There are some complications to the design having to do with how to distinguish these kinds of “expression-only” lambdas from multi-line lambdas, but we can gloss over those for the moment. (Also note that this is the syntax that some languages such as, I believe, Python use for their lambda expression syntax).

The final option we’ve been kicking around is somewhere in the middle of the two:

    Dim ys = xs.Where(x => x < 5)

The fat arrow has reappeared, but now there’s a backslash that introduces the lambda expression. The backslash is supposed to suggest the lambda character (?), but uses a character that is actually on people’s keyboards. The reason for even considering this hybrid syntax is that having an introducing token means we can give a better Intellisense/IDE experience, since the leading “” token allows us to recognize immediately that you’re writing a lambda expression instead of having to guess until we get to the “=>”.

I’m kind of curious what people think. Given the three options:

  1. C#-style, “x => x + 1″
  2. VB-style, “Function(x) x + 1″
  3. Hybrid-style, “x => x + 1″

I’m a little torn between the clarity of #2 and the conciseness of #3, but I may just be smoking crack on #3. There’s nothing intrinsically wrong with #1, but even after staring at it for a long time, it just doesn’t feel, you know, like VB…

Hotfixes are, well, just that…

In response to my entry on VB hotfixes being made more available, Paul L brought up a point that’s worth addressing:

While this is great (and long overdue), the truth of the matter is that most companies do not have the time and resources to download these hotfixes, test them, and then propogate them to other teams. Indeed, after installing *all* of the hotfixes that you list we still had envrionment issues that remain unresolved. Sure, we can contact PSS every time we run into something, but aren’t we supposed to be spending our times working with tools that are just supposed to work out of the box…

I should have emphasized that the hotfixes are, well, hotfixes. We also call them “QFE”s, which stands for “Quick Fix Engineering,” which should give you a further appreciation of their nature. QFEs are produced in response to urgent customer product support requests and although we take as much care as possible with them, they are intended to solve the specific problem and are not put through the extremely rigorous tests that a full release or service pack gets. Thus, installing a hotfix is really only for people who need their particular problem solved. Everyone else should wait for VS 2005 SP1, which is already in beta and will contain lots of other fixes and will be much more rigorously tested. Seriously – if you can wait for SP1, you should. It’ll be much better.

Paul continues with:

Instead, we made a more strategic choice to simply convert all of our VB applications to C# and we haven’t looked back. In each case, the application conversion process took a day or two (thanks to the conversion features of SharpDevelop) and I can certainly say that our development experience has been on orders of magnitude more stable and reliable with the IDE experience than it was with VB.

I feel extremely regretful that the C# experience has been so much more stable for Paul than the VB experience was. I’ve been doing a lot of development work in a mixed C# and VB solution recently and haven’t noticed any difference between the two in terms of stability, but as is obvious from the hotfix and SP situation, there are some problems. There shouldn’t be any difference between the two IDEs, but I think that part of the problems, such as there is, stem from the greater ambitions of the VB IDE. I find it very annoying switching between C# and VB because I’m always missing my background compilation and much more accurate (in my experience) Intellisense when I flip over to C#. This comes directly from the greater integration between the compiler and the IDE, which also means that there’s more opportunity for problems and for us to screw things up.

The interesting thing to see is what happens in Orcas. With a much greater reliance on type information that type inference demands (both for local variable type inference and lambda expression inference), C# is going to need to forge much closer links between their compiler and their IDE, similar to what VB has done. What effect that will have is going to be interesting to see.

Bootstrapping VB

I could have sworn that I’d answered this before, but a Live search on “bootstrap” didn’t turn up anything, so I guess not. Anthony asked:

Do you think you’ll ever get VB to the point where it’s compiler is written in VB? Isn’t that like the ultimate programming language Right of Passage?

I’m not sure whether every major language has gone to the length of compiling itself in itself, but it’s something that would be nice to achieve one of these days with VB. There’s no technical reason I can think of why we couldn’t build the compiler in VB, but since most of the compiler codebase is currently in C++, that’s a pretty big barrier to migration. We wouldn’t even consider trying to move the codebase unless and until there was some compelling reason to do so, and so far that reason hasn’t appeared.

The initial choice of C++, of course, was due to the fact that we didn’t have a working VB .NET compiler to bootstrap us up…