Sunday, January 20, 2008

Demystifying C# 3.0 - Part 4: Lambda Expressions

Source: http://blah.winsmarts.com/2006/05/19/demystifying-c-30--part-4-lambda-expressions.aspx
Demystifying C# 3.0 - Part 4: Lambda Expressions
Posted on 6/30/2006 @ 8:43 PM in #Vanilla .NET 2 comments 5819 views
In the Demystifying C# 3.0, I've already talked about -
a) Demystifying C# 3.0 - Part 1: Implicitly Typed Local Variables "var"b) Demystifying C# 3.0 - Part 2: Anonymous Typesc) Demystifying C# 3.0 - Part 3: Extension Methods
Lets next talk about Lambda Expressions.
The best way I can describe Lambda Expressions are - C# Anonymous Methods, only a lot cooler.
So what is an anonymous method in C# 2.0?
Well y'know you can write code like below in C# 1.x/2.x -
class SomeClass{ delegate void SomeDelegate(); public void InvokeMethod() { SomeDelegate del = new SomeDelegate(SomeMethod); del(); }
void SomeMethod() { Console.WriteLine("Hello"); }}
Well, anonymous methods let you write the above code in a much more "convenient to write terse way" as below -
class SomeClass{ delegate void SomeDelegate(); public void InvokeMethod() { SomeDelegate del = delegate() { Console.WriteLine("Hello"); }; del(); }}
Wunner'ful. What you see above after the "delegate()" stuff is an anonymous method. Even though it's better than the C# 1.x version, it is still quite verbose.
Lambda expressions give you an even more concise, functional syntax using the"=>" token. In fact, the above could now simply be written as
class SomeClass{ delegate void SomeDelegate(); public void InvokeMethod() { SomeDelegate del = () => Console.WriteLine("Hello") ; del(); }}
In general, the syntax is
parameters => expression
Now obviously, even though this is terse, frankly I don't know how you feel about it - I think changing syntax just for the heck of it, dude that's so not cool!! Now it turns out, Lambda expressions aren't simply a cool new way of writing anonymous methods. They are in fact, a functional superset of anonymous methods. Why?
Lambda expressions can "infer" parameter types, even if you omit them. Anonymous methods bitch and moan if you miss out any parameter explicitly.
Lambda expressions can use both statement blocks and expressions. Anonymous methods take only statement blocks - thus making lambda expressions a tad bit more convenient to use.
Lambda expressions can be passed in as arguments. And when you do so, they participate in "Type argument inference" and "method overload resolution" - (WHOAA what are these 2 heavy duty sounding words? - Sit tight, we'll talk about them soon-ish).
Lambda expressions with an expression body can be converted into expression trees. Expression trees is .. well, we haven't discussed that yet ~ so we'll discuss that, when I write a blogpost about Expression Trees.
Lets talk about these one by one -
Lambda expressions can "infer" parameter types, even if you omit them. Anonymous methods bitch and moan if you miss out any parameter explicitly.
Heavy duty words for something as simple as -
(int x) => x + 1 ; // is the same asx => x + 1 ;
In the second instance, the type is being inferred.
Lambda expressions can use both statement blocks and expressions. Anonymous methods take only statement blocks - thus making lambda expressions a tad bit more convenient to use.
Again, heavy duty words for something as simple as -
(int x) => x + 1 ; // is the same as(int x) => { return x + 1; }
In the second instance, we have a statement block, and in the first we have an expression. So the first - is the same as the below, but it is terse and easier to write and understand.
Lambda expressions can be passed in as arguments. And when you do so, they participate in "Type argument inference" and "method overload resolution"
You could pass in Lambda expressions as arguments into a generic method. Lets consider this in an example. Lets say, you had an extension method (what are extension methods?) as shown below -
public static class myExtensions{ public static void SpankIt( this IEnumerable source, Func someParameter) { foreach (T element in source) Console.WriteLine("SPANK " + someParameter(element) + "!!"); }}
You could use the above Extension method a bit like this -
static void Main(string[] args){ List whoToSpank = new List() ; whoToSpank.Add("Monkey") ; whoToSpank.Add("Bannana") ; whoToSpank.SpankIt(c => "Monkey") ;}
And this produces "SPANK MONKEY !!" twice.
But wait a minute. What is "U" in the extension method? If you put a breakpoint in your extension method, you will find out that C# 3.0 is smart enough to infer that "U" is a string. Dude, you never said "String" it "inferred" it based upon what lambda expression you passed in.
You can't do that with anonymous methods, now can you?
Overload resolution is very similar to this, so I will skip explaining that. And yes there are clear laid out rules regarding overload resolution and type-inference, refer to the C# specs for that (I hate regurgitating docs).
Finally -
Lambda expressions with an expression body can be converted into expression trees. Expression trees is well just read this post instead.

Labels: , , ,

0 Comments:

Post a Comment

Subscribe to Post Comments [Atom]

<< Home