Thursday, December 20, 2007

Anatomy Of Lambda Expressions in C# - for beginners

I have been examining LINQ and have come to conclusion that parameter signatures can be downright intimidating in LINQ extension methods! The top of my list are the lambda expressions. I am going to attempt to break down on how to "read" the lambda expressions signatures and maybe save you from going mad and blind!

Lets examine this function: f(x,y) = x+y . This function requires two parameters and returns a result of an addition.

To implement function we could try this:

    public static class Calculator
{
public static int Add(int x, int y)
{
return x + y;
}
}



The problem with this implementation is that we actually "implemented" the meaning of the word Add and bound it to a classifier Calculator. What if the name of the method was MySuperAdd? What if the classifier is unknown at the run time? What if we would like to pass add method to another method?



Lambda





In a not so distant past we have been introduced to delegates in C#. Delegate establishes a contract that specifies the signature of one or more methods. Simply said we are informing a compiler to expect a function f with typed parameters and return values. In C++ world this was a function pointer.



Stage 1 - delegate


Lets describe our function with a delegate:





   1: //Function: First Argument Type int, Second Argument Type int, Return Type int


   2: public delegate int AddDelegate(int a, int b);


   3:  


   4: public class Lambda


   5: {


   6:     public static int AddIt(int a, int b) //function described by the delegate; implementation


   7:     {


   8:         return a + b;


   9:     }


  10:  


  11:     public void InvokeDelegate()


  12:     {


  13:         AddDelegate myFunctionPointer = new AddDelegate(AddIt);


  14:         AddDelegate myFunctionPointer2 = new AddDelegate(CalcImpl.Add);


  15:  


  16:         int result = myFunctionPointer(2, 2);


  17:     }


  18:  


  19:     private static class CalcImpl


  20:     {


  21:         public static int Add(int x, int y)


  22:         {


  23:             return x + y;


  24:         }


  25:     }


  26: }




Although this is a contrived example, it shows that I can create instance of delegate pointing to two different function implementations as long as the target method signature is the same as delegate. Line 13 points to Lambda.AddIt method while Line 14 points to CalcImpl.Add method.



Stage 2 - anonymous delegate


Now lets reduce this a bit using the C# anonymous delegates (since v2.0):





   1: //Function: First Argument Type int, Second Argument Type int, Return Type int


   2: public delegate int AddDelegate(int a, int b);


   3:  


   4: public class Lambda


   5: {


   6:     //public static int AddIt(int a, int b) //function described by the delegate; implementation


   7:     //{


   8:     //    return a + b;


   9:     //}


  10:  


  11:     public void InvokeDelegate()


  12:     {


  13:         // inline function implementation and description 


  14:             // a.k.a anonymous delegate


  15:         AddDelegate myFunctionPointer =


  16:                     delegate(int a, int b)


  17:                     {


  18:                         return a + b;


  19:                     };


  20:  


  21:         AddDelegate myFunctionPointer2 =


  22:                     delegate(int a, int b)


  23:                     {


  24:                         return a + b;


  25:                     };


  26:  


  27:         int result = myFunctionPointer(2, 2);


  28:     }


  29:  


  30: }




I have dispensed with internal implementation (lines 6-9) and have moved implementation detail into anonymous delegate (lines 16-19).



Stage 3 - using lambda token =>


Lets further reduce the code by using the shorter syntax. C# introduces a new lambda token "=>". What our delegate describes is two input parameters, a and b (names are purely arbitrary) and return value. Line 14 shows this transformation:





   1: //Function: First Argument Type int, Second Argument Type int, Return Type int


   2: public delegate int AddDelegate(int a, int b);


   3:  


   4: public class Lambda


   5: {


   6:     //public static int AddIt(int a, int b) //function described by the delegate; implementation


   7:     //{


   8:     //    return a + b;


   9:     //}


  10:  


  11:     public void InvokeDelegate()


  12:     {


  13:        //(First Parameter, Second Parameter) => Return 


  14:         AddDelegate myFunctionPointer = (a, b) => a + b;//delegate describing function


  15:  


  16:         int result = myFunctionPointer(2, 2);


  17:     }


  18:  


  19: }




We have dispensed with creating new instance (new AddDelegate) and we have lost the body (the stuff between {} brackets ). Another thing we have lost is explicit declaration of type. The types of input and return parameters will be inferred by compiler, from our delegate definition (line 2). Visual Studio will give you full intellisense support for a and b types.



Stage 4 - dispensing with our delegate


Now if we could somehow describe the function delegate in some generic way... C# has introduced bunch of new generic functions that help with this exact problem.





   1: //Function: First Argument Type int, Second Argument Type int, Return Type int


   2: //public delegate int AddDelegate(int a, int b); //delegate describing function


   3:  


   4: // Already have delegates describing Function with various number of arguments defined


   5: //public delegate TR Func<TR>();


   6: //public delegate TR Func<T0, TR>(T0 a0);


   7:  


   8: //public delegate TR Func<T0, T1, TR>(T0 a0, T1 a1); <-- This one will work for us


   9:  


  10: //public delegate TR Func<T0, T1, T2, TR>(T0 a0, T1 a1, T2 a2);


  11: //public delegate TR Func<T0, T1, T2, T3, TR>(T0 a0, T1 a1, T2 a2, T3 a3);


  12:  


  13: public class Lambda


  14: {


  15:     public static void InvokeDelegate()


  16:     {


  17:         //Func<First Arg Type, Second Arg Type, Return Type>


  18:         Func<int, int, int> myFunctionPointer = (a, b) => a + b; //delegate describing function


  19:  


  20:         int result = myFunctionPointer(2, 2);


  21:     }


  22:  


  23:  


  24:     public static void FancyThis(Func<int, int, int> interesting)


  25:     {


  26:         Func<Func<int, int, int>, int, int> huh = (f, p) => f(p, 3) + p;


  27:  


  28:         int result = huh(interesting, 5);


  29:     }


  30: }




We can completely dispense with our delegate and use one of generic versions of the function declaration (line 8).  Lines 24-28 demonstrated the ability to pas the function pointers around and than use them as parameters



Now we can do something like this:





   1: class Program


   2: {


   3:     static void Main(string[] args)


   4:     {


   5:  


   6:         Func<int, int, int> substractor = (a, b) => a - b;


   7:  


   8:         Lambda.FancyThis(substractor);


   9:  


  10:         Func<int, int, int> adder = (a, b) => a + b;


  11:  


  12:         Lambda.FancyThis(adder);


  13:  


  14:     }


  15: }




Don't be intimidated



Some of the method signatures look VERY intimidating especially in LINQ world. For example GroupBy method extensions signature:



public static IEnumerable<IGrouping<TKey, TElement>> GroupBy<TSource, TKey, TElement> (
IEnumerable<TSource> source,
Func<TSource, TKey> keySelector,
Func<TSource, TElement> elementSelector,
IEqualityComparer<TKey> comparer
)


Is nothing more than a method that returns a list of groups with a key and value; expects four parameters two of them being delegate types and one being a list (source).



First delegate specifies the key for the group (Quantity) while second delegate specifies what value (ProductID, instead of the element of the list) to take and associate with the group. TSource is usually implied from the type on which you are performing group by.






   1: //key, productID


   2: IEnumerable<IGrouping<int, int>> result2 =


   3:    items.GroupBy(


   4:                     keySelector => keySelector.Quantity,


   5:  


   6:                     elementSelector => elementSelector.ProductID //Projection!


   7:                  );




Source in the above case is being implied from items type...



Hopefully this demystifies the lambda expressions a bit and makes your more comfortable breaking down the complex method signatures.













 




Monday, December 10, 2007

Anatomy Of Lambda Expressions in C# - for beginners

Lets examine this function: f(x,y) = x+y . This function requires two parameters and returns a result of an addition.

To implement function we could try this:

    public static class Calculator
{
public static int Add(int x, int y)
{
return x + y;
}
}



The problem with this implementation is that we actually "implemented" the meaning of the word Add and bound it to a classifier Calculator. What if the name of the method was MySuperAdd? What if the classifier is unknown at the run time? What if we would like to pass add method to another method?



Lambda





In a not so distant past we have been introduced to delegates in C#. Delegate establishes a contract that specifies the signature of one or more methods. Simply said we are informing a compiler to expect a function f with typed parameters and return values. In C++ world this was a function pointer.



Stage 1 - delegate


Lets describe our function with a delegate:





   1: //Function: First Argument Type int, Second Argument Type int, Return Type int


   2: public delegate int AddDelegate(int a, int b);


   3:  


   4: public class Lambda


   5: {


   6:     public static int AddIt(int a, int b) //function described by the delegate; implementation


   7:     {


   8:         return a + b;


   9:     }


  10:  


  11:     public void InvokeDelegate()


  12:     {


  13:         AddDelegate myFunctionPointer = new AddDelegate(AddIt);


  14:         AddDelegate myFunctionPointer2 = new AddDelegate(CalcImpl.Add);


  15:  


  16:         int result = myFunctionPointer(2, 2);


  17:     }


  18:  


  19:     private static class CalcImpl


  20:     {


  21:         public static int Add(int x, int y)


  22:         {


  23:             return x + y;


  24:         }


  25:     }


  26: }




Although this is a contrived example, it shows that I can create instance of delegate pointing to two different function implementations as long as the target method signature is the same as delegate. Line 13 points to Lambda.AddIt method while Line 14 points to CalcImpl.Add method.



Stage 2 - anonymous delegate


Now lets reduce this a bit using the C# anonymous delegates (since v2.0):





   1: //Function: First Argument Type int, Second Argument Type int, Return Type int


   2:     public delegate int AddDelegate(int a, int b);


   3:  


   4:     public class Lambda


   5:     {


   6:         //public static int AddIt(int a, int b) //function described by the delegate; implementation


   7:         //{


   8:         //    return a + b;


   9:         //}


  10:  


  11:         public void InvokeDelegate()


  12:         {


  13:             AddDelegate myFunctionPointer =


  14:                 new AddDelegate


  15:                     (


  16:                 // inline function implementation and description 


  17:                 // a.k.a anonymous delegate


  18:                         delegate(int a, int b)


  19:                         {


  20:                             return a + b;


  21:                         }


  22:                     );


  23:  


  24:             AddDelegate myFunctionPointer2 =


  25:                 new AddDelegate


  26:                     (


  27:                 // inline function implementation and description 


  28:                 // a.k.a anonymous delegate


  29:                         delegate(int a, int b)


  30:                         {


  31:                             return a + b;


  32:                         }


  33:                     );


  34:  


  35:             int result = myFunctionPointer(2, 2);


  36:         }


  37:  


  38:     }




I have dispensed with internal implementation (lines 6-9) and have moved my implementation directly inside the constructor of the new delegate (lines 18-21). We have not gained much except that our implementation seems more inline.



Stage 3 - using lambda token =>


Lets further reduce the code by using the shorter syntax. C# introduces a new lambda token "=>". What our delegate describes is two input parameters, a and b (names are purely arbitrary) and return value. Line 14 shows this transformation:





   1: //Function: First Argument Type int, Second Argument Type int, Return Type int


   2: public delegate int AddDelegate(int a, int b);


   3:  


   4: public class Lambda


   5: {


   6:     //public static int AddIt(int a, int b) //function described by the delegate; implementation


   7:     //{


   8:     //    return a + b;


   9:     //}


  10:  


  11:     public void InvokeDelegate()


  12:     {


  13:        //(First Parameter, Second Parameter) => Return 


  14:         AddDelegate myFunctionPointer = (a, b) => a + b;//delegate describing function


  15:  


  16:         int result = myFunctionPointer(2, 2);


  17:     }


  18:  


  19: }




We have dispensed with creating new instance (new AddDelegate) and we have lost the body (the stuff between {} brackets ). Another thing we have lost is explicit declaration of type. The types of input and return parameters will be inferred by compiler, from our delegate definition (line 2). Visual Studio will give you full intellysense support for a and b types.



Stage 4 - dispensing with our delegate


Now if we could somehow describe the function delegate in some generic way... C# has introduced bunch of new generic functions that help with this exact problem.





   1: //Function: First Argument Type int, Second Argument Type int, Return Type int


   2: //public delegate int AddDelegate(int a, int b); //delegate describing function


   3:  


   4: // Already have delegates describing Function with various number of arguments defined


   5: //public delegate TR Func<TR>();


   6: //public delegate TR Func<T0, TR>(T0 a0);


   7:  


   8: //public delegate TR Func<T0, T1, TR>(T0 a0, T1 a1); <-- This one will work for us


   9:  


  10: //public delegate TR Func<T0, T1, T2, TR>(T0 a0, T1 a1, T2 a2);


  11: //public delegate TR Func<T0, T1, T2, T3, TR>(T0 a0, T1 a1, T2 a2, T3 a3);


  12:  


  13: public class Lambda


  14: {


  15:     public static void InvokeDelegate()


  16:     {


  17:         //Func<First Arg Type, Second Arg Type, Return Type>


  18:         Func<int, int, int> myFunctionPointer = (a, b) => a + b; //delegate describing function


  19:  


  20:         int result = myFunctionPointer(2, 2);


  21:     }


  22:  


  23:  


  24:     public static void FancyThis(Func<int, int, int> interesting)


  25:     {


  26:         Func<Func<int, int, int>, int, int> huh = (f, p) => f(p, 3) + p;


  27:  


  28:         int result = huh(interesting, 5);


  29:     }


  30: }




We can completely dispense with our delegate and use one of generic versions of the function declaration (line 8).  Lines 24-28 demonstrated the ability to pas the function pointers around and than use them as parameters



Now we can do something like this:





   1: class Program


   2: {


   3:     static void Main(string[] args)


   4:     {


   5:  


   6:         Func<int, int, int> substractor = (a, b) => a - b;


   7:  


   8:         Lambda.FancyThis(substractor);


   9:  


  10:         Func<int, int, int> adder = (a, b) => a + b;


  11:  


  12:         Lambda.FancyThis(adder);


  13:  


  14:     }


  15: }




Don't be intimidated



Some of the method signatures look VERY intimidating especially in LINQ world. For example GroupBy method extensions signature:



public static IEnumerable<IGrouping<TKey, TElement>> GroupBy<TSource, TKey, TElement> (
IEnumerable<TSource> source,
Func<TSource, TKey> keySelector,
Func<TSource, TElement> elementSelector,
IEqualityComparer<TKey> comparer
)


Is nothing more than a method that returns a list of groups with a key and value; expects four parameters two of them being delegate types and one being a list (source).



First delegate specifies the key for the group (Quantity) while second delegate specifies what value (ProductID, instead of the element of the list) to take and associate with the group. TSource is usually implied from the type on which you are performing group by.






   1: //key, productID


   2: IEnumerable<IGrouping<int, int>> result2 =


   3:    items.GroupBy(


   4:                     keySelector => keySelector.Quantity,


   5:  


   6:                     elementSelector => elementSelector.ProductID //Projection!


   7:                  );




Source in the above case is being implied from items type...



Hopefully this demystifies the lambda expressions a bit and makes your more comfortable breaking down the complex method signatures.