Demystifying Lambdas in C# 3.0

I’ve had this conversation a few times, so it seems natural that it’d evolve onto my blog in time.  The conversation typically goes like this: “There’s this weird thing I don’t get.  It looks like this: x => x < 6 and like this: Func<int,bool> p.“  Why are these so magical?  How did they come to be?  That’s what we’ll look at here.

Let’s start by clearly defining Lambda.  It’s a function pointer (for the C/C++ among us), or it’s a short-hand way to define a method (for those of us without that much hair loss), and it grew out of C#’s delegates.  They just make it simpler to pass basic (and not so basic) logic to another procedure.

In .NET 1.0, we had delegates.  MSDN defines them as “a type that references a method” or put more simply “a function pointer”.  Somewhere in my class definition, I’d create the delegate definition:

public delegate bool LessThanSixDelegate( int InputVar );

Elsewhere in the class, I’d create the implementation method definition:

public bool MethodName( int InputVar ) {
    return InputVar < 6;
}

Then embedded in some method somewhere I would instantiate this delegate, referencing the MethodName() function:

LessThanSixDelegate methodPointerInstance = new LessThanSixDelegate( MethodName );

Then I’d use the instance like so:

methodPointerInstance( 12 );

That’s .NET 1.0 code, and it’s well worn, and quite verbose.

Fast-forward a few years, and we’re at .NET 2.0, and the latest hotness is “Anonymous Methods” – basically delegates without all the pomp and circumstance:

public delegate bool LessThanSixDelegate( int InputVar );

// ...

LessThanSixDelegate methodPointerInstance = delegate( int InputVar ) { return InputVar < 6; };

We’re making great progress.  I still need the delegate definition, but I don’t need to separate the method that does the work from the instance of the delegate.  I create an inline method – an anonymous method – because the method doesn’t have a name, only the instance has a name.

Fast-forward to .NET 3.0, and we now have Lambdas.  The main goal is to get more terse, avoid redundant characters, and get rid of the delegate definition.  Now we can create the delegate definition and method implementation all at once as we instantiate the instance.

var methodPointerInstance = ( int InputVar ) => { return InputVar < 6; };

They needed a character to denote the difference between input parameters and method body, and to denote it as a quick-built delegate – function pointer – lambda.  The character of choice: “=>”, pronounced “such that”.  My method is basically “take in an int InputVar, and calculate InputVar such that InputVar is less than 6.”

This is gorgeous, but there’s still some redundancy.

If the usage determines the input parameter’s type, we don’t need to specify it.  Let’s simplify by removing it:

var methodPointerInstance = ( InputVar ) => { return InputVar < 6; };

If we have only one line in our method, we don’t need the return or the curly braces.  Let’s simplify it to just this:

var methodPointerInstance = ( InputVar ) => InputVar < 6;

If we only have one input parameter, we can avoid the parens around it and we’re left with this:

var methodPointerInstance = InputVar => InputVar < 6;

If I want to name my input parameter “x” instead of “InputVar”, I could yield this:

var methodPointerInstance = x => x < 6;

Gorgeously tiny, very sweet.

Well, all these simplifications were completely optional.  These two lines are completely identical:

var methodPointerInstance = ( int InputVar ) => { return InputVar < 6; };
var methodPointerInstance = x => x < 6;

I can also choose which of these simplifications I prefer, and leverage that syntax.

Well, what if the assumptions we made while simplifying it don’t hold true?  What if we have zero parameters?  Or we have more than one parameter?  Well, we can’t leave off the parens then.  What if we have more than one line in our function?  Then we can’t leave off the curly braces or return line.  Here’s an example of each:

Zero parameters:

var methodPointerInstance = () => 5 < 6;

Two parameters:

var methodPointerInstance = ( Param1, Param2 ) => Param1 < Param2;

Two line long method body:

var methodPointerInstance = InputVar => {
    int comparer = 6;
    bool result = InputVar < comparer;
    return result;
};

I could also choose to add back in any of the short-cut things that I had removed.  Definitely season to taste.  All else being equal though, I like typing less.

So what of this construct: Func<int,bool>?  That’s just a short-cut way of generically specifying a delegate as a parameter into a method.  Action<T,U,V> is that way too.  Func<> will always return the last parameter and take in all the rest as input parameters.  Action<> will always take in all the parameters and return type is void.  Let’s see each in action:

Func<int,bool> methodPointerInstance = InputVar => InputVar < 6;

This “anonymous method pointer” takes in a single int, and returns a bool.

Func<int,int,bool> methodPointerInstance = (Param1,Param2) => Param1 < Param2;

This func takes in two int parameters and returns a bool.

Action methodPointerInstance = (Param1,Param2) => {
    if ( Param2 ) {
        DoIt(Param1);
    }
};

This action takes in two parameters and returns nothing.

So, now when the method signature intelisense pops up with Func<int,bool> methodSignature, no need to run for the hills.  Just pass in x => x < 6 – a lambda that matches the delegate definition using this cool short-cut syntax.

Lambdas are immensely powerful, and your existing skills in forming delegates to satisfy click event handlers already gives you the skills you need to leverage them.  At the end of the day, they’re just function pointers.  Awesome.

Rob