Lambda Expressions

.Lambda Expressions
Syntax Examples | Delegates | Link Extension Methods | Expression Trees

"C# 3.0 introduced language extensions to support the functional-style programming used with LINQ. These extensions did more than just making LINQ possible. They were added to C# as features which enabled a degree of functional programming for general-purpose use. The C# extensions supported functions as first-class citizens (i.e. they can be passed as a parameter, returned from a function, assigned to a variable). Lambda expressions were one of the extensions that made this degree of support possible. Lambda expressions contain a concise syntax for creating anonymous functions."



Procedural vs Functional Programming

Two fundamental architectures for computer programming languages are Procedural and Functional. Procedural (a.k.a Imperative) programming tells the computer step-by-step "how to do something", while Functional (a.k.a. Declarative) programming tells the computer "what results you want". Most of the mainstream languages where designed for procedural programming. However SQL is a familiar form of functional programming. While some languages are purely procedural (e.g. C) or purely functional (e.g. Haskell), other languages are evolving to contain aspects of functional programming mixed with their procedural foundations (e.g. C# 3.0, Java SE 7, 8 ).

Most programmers learn to program using a procedural style. Functional programming can take some getting use to as it requires a different approach. Functional languages are inherently recursive and they contain no structures for looping or iteration. In functional languages variables are immutable and can only be assigned a value which is returned from a function. Immutable variables help create a characteristic called "purity" by ensuring that functions are not allowed to change external data (i.e. no side effects possible). Purity also requires that the value returned from a function is only dependent upon the function input values. Purity is desirable in parallelization of code which makes better use of multicore processors. The independent nature of pure code is also useful in coding applications which require scalability and fault tolerance. Erlang is a functional programming language designed by Ericsson to provide the concurrency, fast response, fault tolerance, and scalability needed for telephony systems. Today Erlang is an open-source language used in telecoms, banking, e-commerce, computer telephony and instant messaging.

The MSDN article Functional Programming vs. Imperative Programming goes into considerable detail comparing functional with procedural programming. Some of the differences include:

  • Procedural (Imperative) Programming
    • Most mainstream languages were initially designed to support imperative (procedural) programming. (e.g. C#, Java, C++, etc).
    • Developers write code that describes the steps the computer must take to accomplish the goal. This involves keeping track of state (variables) and controlling the flow of execution.
    • Primary Flow Control: loops, conditionals, method calls.
  • Functional (Declarative) Programming
    • Developers compose the program as a set of functions. Values returned by a function are only dependent upon it's input, so there is not state to track.
    • Primary Flow Control: function calls, including recursion.
    • Aspects of functional programming include:
      • Recursion - is heavily used and is the only way to loop or iterate.
      • Lazy Evaluation - defer the computation of values until they are needed.
      • Higher-order Functions - functions that take other functions as their arguments.
      • Purity - computations can not be influenced by external actions.
      • Immutable Data - "variables" can only be assigned a value once.
      • Referential Transparency - computations yield the same value each time they are invoked.


 Book recommendation: Erlang Programming By Francesco Cesarini, Simon Thompson (ISBN-13: 978-0596518189).



Lambda Expressions

Lambda expressions provide a concise syntax for creating anonymous functions. The syntax for a lambda expression looks similar to the syntax for an assignment statement, in that you have a value on the left (input parameters) , an operator in the middle (=>, read as "goes to"), and a value on the right (function logic). Also like the assignment statement, the lambda expression is also right-associative.

The syntax and properties are illustrated with the following examples which use delegates. More information about delegates can be found in my Delegates article.

  1. Single parameter lambda expression - the delegate named Transform is used to hold the function logic described by the lambda expression (x => x * x;) and associate the function logic with a name (square).

  2. Double parameter lambda expression - the signature for delegate (i.e. return type, type and number of input parameters) must match the lambda expression, so new delegate Transform2 was created. Note if more than one input parameter is used in the lambda expression, the lambda expression must have parenthesis around the input parameter with a comma separating the parameters. If no input parameters are used, an empty set of parenthesis must be used on the left side of the lambda operator.

  3. Lambda expression closure - note how the myInt variable was used inside the lambda expression even though it was not passed in as a parameter. This is possible because lambda expression have a property called closure. Closure allows the lambda expression access variables that are in scope at the time the expression is declared, without the variable being explicitly passed in as a parameter.

  4. Specify type of input parameters - the compiler will try to infer the type of the input parameters used in the lambda expression. If it can not correctly infer the type, it will be necessary to explicitly define the type of the input parameters.



Lambda Expression Syntax Examples

/*****************************************
*   Lambda Expression Syntax Examples    *
******************************************/
using System;

namespace LambdaSyntaxExamples
{
    // Custom delegate declarations
    delegate int Transform(int i);
    delegate int Transform2(int i, int j);
    delegate bool Transform3(int i, string s);

    class Program
    {
        static void Main()
        {  
            // 1. Single parameter lambda expression
            Transform square = x => x * x;
            System.Console.WriteLine(square(5)); // Prints: 25

            // 2. Double parameter lambda expression
            Transform2 square2 = (x,y) => x * y;
            System.Console.WriteLine(square2(5, 5)); // Prints: 25

            // 3. Lambda expression closure
            int myInt = 7;
            Transform adder = x => x + myInt;
            System.Console.WriteLine(adder(5)); // Prints: 12

            // 4. Specify type of input parameters
            Transform3 stringSize = (int x, string s) => s.Length > x;
            Console.WriteLine(stringSize(3, "ABC")); // Prints: False
        }
    }
}

Top


Lambda Expression Uses

Three areas where lambda expressions are used in C# include:

  1. Delegates (Events) - A delegate is a type which holds method reference(s) in an object. Delegates in C# have evolved to the point where we have built-in generic delegates which use lambda expressions. The following example contains two lambda expressions:
    1. The first is used to define the event handler, which will print the player's score and the current high score when a new score is added to the collection.

    2. The second is used in a function delegate, which returns the player who currently has the highest score.

    More information about delegates can be found in my Delegates article.

  2. LINQ Extension Method - as an alternative to the traditional LINQ query syntax, you can use a lambda expression inside a LINQ extension method. The following example compares the two different approaches (query syntax vs method syntax) for performing several queries.

  3. Expression Tree - permit lambda expressions to be represented as data structures instead of executable code.




Delegates

.Lambda Delegates




Lambda Expression in Delegates Example

using System;
using System.Linq;
using System.Collections.ObjectModel;

namespace LambdaDelegates
{
    class Program
    {
        class Player
        {
            public string Name { get; set; }
            public int Score { get; set; }

            // ToString override
            public override string ToString()
            {
                return string.Format("{0} ({1})", Score, Name);
            }
        }

        static void Main()
        {
            System.Console.WriteLine(" ------------------------------- ");
            System.Console.WriteLine(" ---    Lambda Delegates     --- ");
            System.Console.WriteLine(" ------------------------------- ");

            int playerScore = 0;
            string playerName = "";
            ObservableCollection<Player> playerCollection = new ObservableCollection<Player>();

            // 1. Use lambda expression to define event handler
            playerCollection.CollectionChanged += (s, e) =>
            {
                // 2. Use lambda expression to get player with max score
                Console.WriteLine("{0}, your score is: {1} ... Highest score is: {2}",
                        playerName, playerScore, playerCollection.Max(x => x.Score));
            };

            // Add new player scores
            System.Console.WriteLine("\n ---  New Scores for Players  -- ");

            playerScore = 987;
            playerName = "Merlin";
            playerCollection.Add(new Player
            {
                Name = playerName,
                Score = playerScore
            });

            playerScore = 999;
            playerName = "Gandalf";
            playerCollection.Add(new Player
            {
                Name = playerName,
                Score = playerScore
            });

            playerScore = 945;
            playerName = "Saruman";
            playerCollection.Add(new Player
            {
                Name = playerName,
                Score = playerScore
            });

            // Print all players in collection
            System.Console.WriteLine("\n ---   Collection Contents   --- ");
            foreach (Player thePlayer in playerCollection)
                System.Console.WriteLine(thePlayer);
            System.Console.WriteLine();
        }
    }
}

Top




LINQ Extension Methods

There are two flavors for expressing a LINQ query; they go by different names depending on the source you are reading, the two most common culprits are: Query (or Query Expression) and Method Chaining (or Fluent). In some circles, debates will range long and loud over which method to use as well as what to call it.

LINQ Query Syntax vs Fluent Syntax
// method syntax
var names = collection.Count(item => item.Name == "Fred");

// query syntax
var names = (from item in collection
            where item.Name == "Fred"
            select item).Count()


var names = collection.Where(item => item.Name == "Fred")
                      .OrderBy(item => item.Age)
                      .Select(item => item.Name);

var names = from item in collection
            where item.Name == "Fred"
            order by item.Age
            select item.Name;


        int[] numbers = { 5, 10, 8, 3, 6, 12};

        //Query syntax:
        IEnumerable numQuery1 = 
            from num in numbers
            where num % 2 == 0
            orderby num
            select num;

        //Method syntax:
        IEnumerable numQuery2 = numbers.Where(num => num % 2 == 0).OrderBy(n => n);

        foreach (int i in numQuery1)
        {
            Console.Write(i + " ");
        }
        Console.WriteLine(System.Environment.NewLine);
        foreach (int i in numQuery2)
        {
            Console.Write(i + " ");
        }


Top




Expression Trees

Expression trees represent code in a tree-like data structure, where each node is an expression, for example, a method call or a binary operation such as x < y. You can compile and run code represented by expression trees. This enables dynamic modification of executable code, the execution of LINQ queries in various databases, and the creation of dynamic queries.

When a lambda expression is assigned to a variable of type Expression, the compiler emits code to build an expression tree that represents the lambda expression. The C# and Visual Basic compilers can generate expression trees only from expression lambdas (or single-line lambdas). It cannot parse statement lambdas (or multi-line lambdas).

The following code example demonstrates how to compile an expression tree and run the resulting code

// Creating an expression tree.
Expression> expr = num => num  result = expr.Compile();

// Invoking the delegate and writing the result to the console.
Console.WriteLine(result(4));

// Prints True.

// You can also use simplified syntax
// to compile and run an expression tree.
// The following line can replace two previous statements.
Console.WriteLine(expr.Compile()(4));

// Also prints True.


Dynamic queries are useful when the specifics of a query are not known at compile time. For example, an application might provide a user interface that enables the end user to specify one or more predicates to filter the data. In order to use LINQ for querying, this kind of application must use expression trees to create the LINQ query at runtime.

The easiest way to generate an expression tree is to create an instance of the Expression type, where T is a delegate type, and assign a lambda expression to this instance. Let’s take a look at the code.

// Creating an expression tree by providing a lambda expression.
Expression> printExpr = (arg) => Console.WriteLine(arg);

// Compiling and invoking the expression tree.
printExpr.Compile()(10);
// Prints 10.



On the other hand, not every lambda expression can be implicitly converted into an expression tree. For example, multiline lambdas (also called statement lambdas) cannot be implicitly converted into expression trees.

// You can use multiline lambdas in delegates.

Action printTwoLines = (arg) =>
{
  Console.WriteLine("Print arg:");
  Console.WriteLine(arg);
};

// But in expression trees this generates a compiler error.
Expression> printTwoLinesExpr = (arg) =>
{
  Console.WriteLine("Print arg:");
  Console.WriteLine(arg);
};



With the introducing of LINQ in the .NET Framework 3.5 timeframe, we ended up adding expression trees to the framework as a way to represent code as data.

Consider the following query expression:

var res = from p in db.Products 
          where p.UnitPrice > 100 
          select p.ProductName;



Given this, we can’t say much about the query just yet. All we know is that from a language’s point of view, we can “desugar” the above into the below:

var res = db.Products 
          .Where(p => p.UnitPrice > 100) 
          .Select(p => p.ProductName);



From this point on, regular method resolution rules kick in to find a Where method on db.Products, and to find a Select method on the result of calling Where. The argument to both those methods is a lambda expression and here’s where the flexibility comes from. Lambda expressions by themselves don’t have a type:

var twice = (int x) => x * 2;



Though the right-hand side seems to have all the information to infer a type (going from int to an expression of type int, ought to be Func right?) the above doesn’t compile. Lambda expressions can be assigned to variables of two distinct types: regular delegates or expression trees thereof. The below illustrates this:

Func             twiceD = x => x * 2; 
Expression> twiceE = x => x * 2;



The first one is shorthand for an anonymous method we already supported in C# 2.0:

Func             twiceD = delegate(int x) { return x * 2; };



However, the second one gives rise to quite a bit more of generated code; in particular, code is emitted that constructs an expression tree at runtime to represent the code the user wrote as data. Given this code, the library function calls (like Where and Select in case of LINQ) can consume that expression tree to analyze the code the user wrote, extracting the intent and turning it into execution in whatever way is right for the task at hand (e.g. by cross-compiling the expression into a target query language like SQL). In particular, the twiceE lambda expression gets turned into:

ParameterExpression x = Expression.Parameter(typeof(int), “x”); 
Expression> twiceE = Expression.Lambda>( 
    Expression.Multiply( 
        x, 
        Expression.Constant(2) 
    ), 
    x 
);


Top



Reference Articles

Top