C# 3.0 for mere mortals, part 5: Lambda expressions

Time to continue with the longest running series on C# 3.0.


Lambda expressions originated from lambda calculus and found its way into functional languages such as Lisp and Haskel. Lambda calculus is all about calculations with functions. Functional programming on the other hand uses the application of functions to express what should be computed, not how it should be computed as in imperative programming. One of the key points of functional programming is the lazy evaluation of the functions. This gives a tremendous power, and I will revisit this topic when we talk about expressions trees.


C# developers can think of lambda expressions as the natural progression from delegates, to anonymous methods and finally to lambda expressions. Lambda expressions are about a very compact notation for “simple” functions. Let’s see that progression in action.


Take some delegate type:



public delegate string AlarmDelegate(int counter);


A normal delegate instance would need to refer to an existing and declared function inside some type.



public class FromDelegateToLambda


{


  public void Demo()


  {


    // Conventional delegate


    AlarmDelegate del = new AlarmDelegate(OnAlarm);


  }


 


  public string OnAlarm(int counter)


  {


    return counter.ToString();


  }


}


C# 2.0 introduced the anonymous method, where you could define the method body to which a delegate object should refer, without a formal method signature declaration. The compiler would take care of the creation of a method for you. That would make the delegate instantiation like so:



// Anonymous delegate


AlarmDelegate del2 = delegate (int c) { return c.ToString(); };


A lot compacter as you can see. But, it can be even shorter. That’s where lambda expressions come in.



// Lambda expression


AlarmDelegate del3 = (int c) => c.ToString();


A lambda expression leaves out most of the syntax that is not really necessary for comprehension or compilation. The compiler can sometimes even determine the type of the input parameter c from the signature of the delegate. If that is the case, even the typing of the input parameters can be left out.



// Even shorter lambda expression


AlarmDelegate del3 = c => c.ToString();


Some other examples for lambda expressions will give you a quick insight into what is possible:



n => (n-1)*(n-2)                // simple calculus


s => s.ToUpper()                // invoking methods


(int x) => x++                  // explicit typing


(x, y) => x ^ y                // multiple parameters


(x) => { return x++; }          // statement body


() => (new Random()).Next(100)  // no parameters


The shorter lambda expressions usually have a expression body, meaning that there is only a single expression after the => sign. Alternatively you can have a statement body that you can instantly recognize from the curly braces. The May 2006 CTP does support both, but the latter gives incorrect syntax errors in red squigglies. Anonymous methods must have (only) a statement body, so this is one up for lambda expressions. Especially so, since lambda expressions with an expression body can be converted into an expression tree. Again, more on that when we cover expression trees.


There is some discussion as to how to pronounce the => in the expression. Depending on what the expression does it could be



  • “such that”
    For predicates: (Blog b) => b.Title == “Alex Thissen Weblog Build 1.15.10.1971”
  • “becomes”
    For projections with anonymous types: b => new { BlogName = b.Name, Title = b.Title }
  • “goes to”
    No idea when you would want this.

The pronounciations I came up with are depending on the return value if any:



  • n => n++
    Given n return n++
    For functions that have a return value
  • (Blog b) => b.Delete()
    Given b do b.Delete()
    For void return functions

Finally, as you might expect there are only that many method signatures available if you use generics. When you limit the use of ref and out parameters the set is even smaller. The only difference would be the number of arguments. The .NET Framework 3.5 will define a set of delegate types that are primarily meant for lambda expressions. Here is the list:



public delegate T Func<T>();


public delegate T Func<A0, T>(A0 arg0);


public delegate T Func<A0, A1, T>(A0 arg0, A1 arg1);


public delegate T Func<A0, A1, A2, T>(A0 arg0, A1 arg1, A2 arg2);


public delegate T Func<A0, A1, A2, A3, T>(A0 arg0, A1 arg1, A2 arg2, A3 arg3);


These delegates define functions that have 0, 1, 2, 3 and 4 parameters and return some type T. This return type is always last in the generic list. With these types you can define a delegate type of the form AlarmDelegate as Func<int, string>. There is no need to define a new delegate type.


Previous parts:



  1. Extensions methods
  2. Implicitly typed local variables and arrays
  3. Anonymous types
  4. Object and collection initializers

Advertisements
This entry was posted in Uncategorized. Bookmark the permalink.

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out /  Change )

Google photo

You are commenting using your Google account. Log Out /  Change )

Twitter picture

You are commenting using your Twitter account. Log Out /  Change )

Facebook photo

You are commenting using your Facebook account. Log Out /  Change )

Connecting to %s