Chapter 5
Understanding Lambda Expressions and Closures

In This Chapter

Image Understanding the Evolution from Function Pointers to Lambda Expressions

Image Writing Basic Lambda Expressions

Image Dynamic Programming with Lambda Expressions

Image Lambda Expressions and Closures

Image Currying

“In wisdom gathered over time I have found that every experience is a form of exploration.”

—Ansel Adams

Hardware capabilities are way ahead of software capabilities, and customer demands are ahead of hardware and software. Holography, instant on and off computers, no moving parts, infinite storage, limitless speed, dependability, and 100% uptime are just a few features that would be great to have.

Businesses and people ask for and need evermore powerful software applications. For programmers, this means code has to do more. Creating code is a function of time and money. Programmers need to be able to use higher and higher levels of abstraction to write code that does more with less and that consumes less time and money. All of this implies code compression—fewer bits of code to do substantially more, hence Lambda Expressions.

Lambda Expressions are based on functional calculus—Lambda Calculus—from the 1930s, and Lambda Expressions exist in other languages. (Check www.wikipedia.org for a brief history of Lambda Calculus.)

Think of Lambda Expressions as brief inline functions whose concise nature is an ideal fit for LINQ. This chapter looks at the evolution path to Lambda Expressions, how to write and use Lambda Expressions, closures, and currying.

Understanding the Evolution from Function Pointers
to Lambda Expressions

In the 1970s Brian Kernighan and Dennis Ritchie brought us function pointers in C (see Listing 5.1). A function is referenced by an address, which is just a number, after all. Function pointers led to the notion of events—really just function pointers—and event handlers. Event handlers evolved into delegates and multicast delegates in .NET (see Listing 5.2). (Remember, fundamentally, we are still talking about function pointers under the hood but with nicer window treatments.) Delegates were compressed into anonymous delegates in .NET 2.0. Anonymous delegates lost some weight by eliminating the function name, return type, and parameter types (shown in Listing 5.3), and anonymous expressions have evolved into Lambda Expressions in Listing 5.4.

Listing 5.1 A C++ Function Pointer Demo Where the Statement Beginning with typedef Defines the Function Pointer Named FunctionPointer

// FunctionPointer.cpp : main project file.
#include “stdafx.h”
using namespace System;
typedef void (*FunctionPointer)(System::String ^str);
void HelloWorld(System::String ^str)
{
    Console::WriteLine(str);
    Console::ReadLine();
}

int main(array<System::String ^> ^args)
{
FunctionPointer fp = HelloWorld;
fp(L”Hello World”);
return 0;
}

Listing 5.2 A C# Demo That Shows the Simpler Syntax of Function Pointers, Called Delegates in C#

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;

namespace CSharpFunctionPointer
{
  class Program
  {
    delegate void FunctionPointer(String str);

    static void Main(string[] args)
    {
      FunctionPointer fp = HelloWorld;
      fp(“Hello World!”);
    }

    static void HelloWorld(string str)
    {
      Console.WriteLine(str);
      Console.ReadLine();
    }
  }
}

Listing 5.3 Identical Behavior to Listing 5.2, This Code Demonstrates an Anonymous Delegate

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;

namespace CSharpAnonymousDelegate
{
  class Program
  {
    delegate void FunctionPointer(string str);

    static void Main(string[] args)
    {
      FunctionPointer fp = delegate(string s)
      {
        Console.WriteLine(s);
        Console.ReadLine();
      };

      fp(“Hello World!”);
    }
  }
}

Listing 5.4 A C# Example Demonstrating a Very Simple Lambda Expression Playing the Role of Delegate—s ⇒ Console.WriteLine(s);

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;

namespace CSharpAnonymousDelegate
{
  class Program
  {
    delegate void FunctionPointer(string str);

    static void Main(string[] args)
    {
      FunctionPointer fp =
        s ⇒ Console.WriteLine(s);

      fp(“Hello World!”);
      Console.ReadLine();
    }
  }
}

Using our weight-loss analogy, Lambda Expressions eliminated the delegate keyword, function header, parameter types, brackets, and return keyword (see Listing 5.4). This very concise grammar for Lambda Expressions is not plain old esoterrorism (esoteric code for the sole purpose of terrorizing programmers). Lambda Expressions’ concise nature makes it easy for these smallish functions to fit into new constructs that support LINQ.

A Lambda Expression is a concise delegate. The left side (of the ⇒) represents the arguments to the function and the right side is the function body. In Listing 5.4, the Lambda Expression is assigned to the delegate FunctionPointer, but .NET 3.5 defines anonymous delegates like Action<T> and Func<T>, which can be used instead of the more formal, longer delegate statement. This means that you don’t have to define the delegate statement (as shown in Listing 5.4). Listing 5.5 shows the revision of Listing 5.4, replacing the delegate statement with the generic Action<T> delegate type.

Listing 5.5 Assigning the Lambda Expression to a Predefined Generic Delegate

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;

namespace LambdaExpressionWithGenericAction
{
  class Program
  {
    static void Main(string[] args)
    {
      System.Action<string> fp =
        s ⇒ Console.WriteLine(s);

      fp(“Hello World!”);
      Console.ReadLine();
    }
  }
}

In Listing 5.5, System.Action<T> is used instead of a custom delegate, as demonstrated in Listing 5.4.

Writing Basic Lambda Expressions

The System namespace defines generic delegates Action, Func, and Predicate. Action performs an operation on the generic arguments. Func performs an operation on the argument or arguments and returns a value, and Predicate<T> is used to represent a set of criteria and determine if the argument matches the criteria. Lambda Expressions can be assigned to instances of these types or anonymous types. Or, Lambda Expressions can be used as literal expressions to methods that accept Func, Action, or Predicate arguments.

This section looks at examples of Lambda Expressions that match each of these generic delegate types, takes a side trip through automatic properties, and shows ways to use these capabilities within the newer features of .NET.

Automatic Properties

Automatic properties are not directly or only related to Lambda Expressions, but automatic properties are relevant to the subject of condensed code and letting the framework do more of the labor.

The basic idea behind automatic properties is that many times, programmers define properties that are just wrappers for fields and nothing else happens. Historically, the programmer writes the field declaration, and the property header, getter, and setter, returning the field or setting the field to the value keyword, respectively. Using properties instead of fields is a recommended practice, but if there are no additional behaviors, automatic properties allow the compiler to add the field, getter, and setter. All the programmer has to do is write the property header.

However, there is a caveat to using automatic properties. You will save some time not writing the whole property and field definition, but you cannot use the field variable in your code. To get around this, you just use the property. Listing 5.6 demonstrates an IronChef class that has two automatic properties: Name and Specialty.

Listing 5.6 Automatic Properties and Named Type Initialization Save Time

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;

namespace AutomaticProperty
{
  class Program
  {
    static void Main(string[] args)
    {
      IronChef Batali = new IronChef{
        Name=”Mario Batali”, Specialty=”Italian” };
      Console.WriteLine(Batali.Name);
      Console.ReadLine();
    }
  }

  public class IronChef
  {
    public string Name{ get; set; };
    public string Specialty{ get; set; }
  }
}

Listing 5.6 defines the class IronChef with the automatic properties Name and Specialty. Notice that you don’t need to include the property method bodies. Also notice that you don’t need a constructor. With named type initialization (see Chapter 2, “Using Compound Type Initialization”) and automatic properties, simple classes can now be defined with many fewer lines of code and the compiler completes the definition (see the MSIL in Figure 5.1).

FIGURE 5.1 The snapshot from Intermediate Language Disassembler (ILDASM) shows that our IronChef class is provided with getters, setters, and backing fields by the compiler.

Image

Automatic properties implicitly instruct the compiler to generate what is referred to as a backing field and these fields are annotated with the CompilerGeneratedAttribute.

Reading Lambda Expressions

Lambda Expressions are written with a left side, the symbol, and a right side, as in (x,y) ⇒ x + y;. The left side represents the input arguments and the right side is the expression to be evaluated. For example

(x,y) ⇒ x + y;

is read x and y goes to—or as I read it gosinta—the function x + y. Implicit in the expression is the return result of x + y. The input argument or arguments can be inferred and generated by the compiler, called implicit arguments, or expressed explicitly by you. The preceding Lambda Expression can also be rewritten as

(int x, int y) ⇒ x + y;

Listing 5.7 shows an example that uses explicit arguments, although doing so is probably just extra typing on your part. The explicit input argument statement is shown in bold.

Listing 5.7 A Lambda Expression Demonstrating Explicit Argument Types

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;

namespace ExplicitLambdaArguments
{
  class Program
  {
    static void Main(string[] args)
    {
      Func<int, int, int> add =
        (int x, int y) ⇒ x + y;
      Console.WriteLine(add(3, 4));
      Console.ReadLine();
    }
  }
}

In Listing 5.7, the generic Func<T,T,TResult> delegate type is used to represent the Lambda Expression referred to by the variable add.

Lambda Expressions Captured as Generic Actions

The generic Action delegate lets you capture behavior as an invokable object. Simply provide the parameter types for the Action, assign it a Lambda Expression, and you are up and running.

Listing 5.8 demonstrates using multiple parameters, including a string and TextWriter, which supports sending output to anything that is an instance of a TextWriter, including the Console. In Listing 5.9, the Array.ForEach<T> generic method is demonstrated, accepting an Action<T>, which supports iterating over an Array<T> of objects.

Listing 5.8 Redirecting Output Using an Action<T, T> and a Lambda Expression

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Diagnostics;
using System.IO;
namespace LambdaExpressionAction
{
  class Program
  {
    static void Main(string[] args)
    {
      Action<string, TextWriter> print =
        (s, writer) ⇒ writer.WriteLine(s);
      print(“Console”, Console.Out);
      StreamWriter stream = File.AppendText(“c:\temp\text.txt”);
      stream.AutoFlush = true;
      print(“File”, stream);
      Console.ReadLine();
    }
  }
}

Listing 5.9 The Output from the Action michiganSalesTax Is Fed into the Action print; the Results Are Printed Using the Array.ForEach Generic Method

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;

namespace ForEachWithActionLambda
{
  class Program
  {
    static void Main(string[] args)
    {
      Action<double> print =
          amount ⇒ Console.WriteLine(“{0:c}”, amount);
      Action<double> michiganSalesTax =
        amount ⇒ print(amount *= 1.06);

      var amounts = new double[]{
        10.36, 12.00, 134};

      Array.ForEach<double>(amounts, michiganSalesTax);
      Console.ReadLine();
    }
  }
}

In Listing 5.9, print uses a Lambda Expression to send a double to the Console formatted as a currency value. The Lambda Expression represented by michiganSalesTax adds 6% to the input double and sends the result to print. Near the end of Listing 5.9, the Array.ForEach generic method is used to iterate over each of the amounts and call michiganSalesTax. (It would sure be nice if those tax numbers went southward once in a while.)

Searching Strings

If you piece some of the elements from prior chapters together, it is easy to see how the mosaic of progression has evolved to LINQ queries. So far, you have learned about extension methods, anonymous types, and, now, Lambda Expressions (among other things). For instance, you know that you can use array initializer syntax and assign the results to an anonymous type, letting the compiler generate the details. Further, you know that arrays implement IEnumerable and you can add behaviors via extension methods. From Chapter 3, “Defining Extension and Partial Methods,” you know that IEnumerable has been extended to include generic methods such as Where<T> that accept predicates—much like WHERE in Structured Query Language (SQL)—and that these predicates can be expressed as Func<TSource,TResult> return types or literal Lambda Expressions.

Combining all of this knowledge, you can use Lambda Expressions as arguments to Where<T> and define short-and-sweet searches, for example, with a very few lines of code. Listing 5.10 demonstrates an anonymous type initialized by an array initializer, use of the Where<T> with a Lambda Expression predicate to filter the strings (recipes) that have Chicken, and the ForEach with a second Lambda Expression that writes each found item. This style of programming (in Listing 5.10) is referred to as functional programming.

Listing 5.10 Combining Anonymous Types, Array Initializers, Lambda Expressions, Actions, and Extension Methods to Search and Display Strings That Contain a Keyword

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;

namespace Searching
{
  class Program
  {
    static void Main(string[] args)
    {
      var recipes = new[]{
        “Crepes Florentine”, “Shrimp Che Paul”,
        “Beef Burgundy”, “Rack of Lamb”,
        “Tacos”, “Rosemary Roasted Chicken”,
        “Juevos Rancheros”, “Buffalo Chicken Nachos”};

      var results = recipes.Where(
        s⇒s.Contains(“Chicken”));

      Array.ForEach<string>(results.ToArray<string>(),
        s ⇒ Console.WriteLine(s));
      Console.ReadLine();

    }
  }
}

Listing 5.11 provides a variation on the search behavior by finding odd numbers in a short Fibonacci sequence. This version uses a generic List<int>, a Lambda Expression assigned to a Predicate<int> initialized by a Lambda Expression, and the List<T>.FindAll method—that accepts a predicate. The results are displayed by the ObjectDumper. ObjectDumper was implemented as demo code for Visual Basic (VB) but might or might not ship with .NET 3.5. (The ObjectDumper is installed with sample code at C:Program FilesMicrosoft Visual Studio 9.0Samples1033CSharpSamples.zip.)

Listing 5.11 A Variation on Searching Behavior Using List<T>’s FindAll and a Predicate Initialized with a Lambda Expression

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;

namespace FindingNumbers
{
  class Program
  {
    static void Main(string[] args)
    {
      List<int> fiboList = new List<int>();
      fiboList.AddRange(
        new[]{1,1,2,3,5,8,13,21,34,55});

      Predicate<int> match = n ⇒ n % 2 == 1;
      var odds = fiboList.FindAll(match);

      ObjectDumper.Write(odds);
      Console.ReadLine();
    }
  }
}

Lambda Expressions Captured as Generic Predicates

The Predicate<T> generic delegate accepts an argument indicated by the parameter T and returns a Boolean. Predicate<T> is used in functions like Array.Find and Array.FindAll.Predicate<T> can be initialized with a regular function, an anonymous delegate, or a Lambda Expression.

In the example in Listing 5.12 (based on a Windows Form project named FindSquares), the code draws a hundred random rectangles and then uses a Lambda Expression assigned to Predicate<Rectangle> and only draws the rectangles whose area is less than or equal to a target range. Originally, a hundred rectangles are created and a Timer paints some number of rectangles every two and a half seconds. The Lambda Expression is on the following line:

Predicate<Rectangle> area = rect ⇒ (rect.Width * rect.Height) <= random.Next(200)
*

random.Next(200));

Listing 5.12 Demonstrating Predicate<T> Initialized with a Lambda Expression

using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Windows.Forms;

namespace FindSquares
{
  public partial class Form1 : Form
  {
    public Form1()
    {
      InitializeComponent();
    }

    Rectangle[] rects = new Rectangle[100];
    private void Form1_Load(object sender, EventArgs e)
    {
      Random random = new Random(DateTime.Now.Millisecond);
      int x, y, width, height;

      for(int i=0; i<100; i++)
      {
        x = random.Next(this.ClientRectangle.Width / 2);
        y = random.Next(this.ClientRectangle.Height / 2);
        width = random.Next(200);
        height = random.Next(200);
        rects[i] = new Rectangle(x, y, width, height);
      }
    }

    private void Form1_Paint(object sender, PaintEventArgs e)
    {
      Random random = new Random(DateTime.Now.Millisecond);
      Predicate<Rectangle> area = rect ⇒
        (rect.Width * rect.Height) <= (random.Next(200) *
        random.Next(200));

      Rectangle[] matches = Array.FindAll(rects, area);
      e.Graphics.Clear(this.BackColor);

      foreach(var rect in matches)
        e.Graphics.DrawRectangle(Pens.Red, rect);
      e.Graphics.DrawString(“Found:” + matches.Length.ToString(),
        this.Font, Brushes.Black, 10, ClientRectangle.Height - 40);
    }

    private void timer1_Tick(object sender, EventArgs e)
    {
      Invalidate();
    }
  }
}

Binding Control Events to Lambda Expressions

It is worth remembering that Lambda Expressions are just very short functions, basically inline functions. Therefore, you can assign a Lambda Expression anywhere you would use a function or anonymous delegate. Remember, as is shown in Listing 5.13, the left side of the <= operator is the inputs and the right side represents the method body. Therefore, to match a typical EventHandler, you need the left side to have an object and EventArgs inputs and the right side to do the typical kinds of things you would do with more verbose event handlers.

Listing 5.13 Using Lambda Expressions for Everyday Event Handlers

using System;
using System.Collections.Generic; 
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Windows.Forms;

namespace LambdaEventHandlers
{
  public partial class Form1 : Form
  {
    public Form1()
    {
      InitializeComponent();
      button1.Click += (s, e) ⇒ MessageBox.Show(“Click!”);
    }
  }
}

Dynamic Programming with Lambda Expressions

You can begin exploring how Lamba Expressions support LINQ queries by seeing how Lambda Expressions are used in extension methods such as Select<T>, Where<T>, or OrderBy<T>. (Of course, more extension methods than these exist, as more capabilities of LINQ queries are built on top of these extension methods, but you get the general idea.)

This section explores Select<T>, Where<T>, and OrderBy<T>. LINQ fundamentals begin in Chapter 6, “Using Standard Query Operators,” and LINQ keywords are explored in that chapter; just remember that underneath those capabilities are extension methods and Lambda Expressions.

Using Select<T> with Lambda Expressions

Suppose you have an array of integers. You could simulate the SELECT * behavior of SQL queries by initializing the Select extension method with n ⇒ n. n ⇒ n means that n is the input and you want to return n. Listing 5.14 shows a very simple Select usage. Select returns an IEnumerable<T> instance, where T is the type of object returned by the Lambda Expression.

Listing 5.14 A Simple Example That Demonstrates the Extension Method Select<T>

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;

namespace SelectLambda
{
  class Program
  {
    static void Main(string[] args)
    {
      var numbers = new int[]{1,2,3,4,5,6};
      foreach(var result in numbers.Select(n ⇒ n))
        Console.WriteLine(result);
      Console.ReadLine();
    }
  }
}

In the example, the code doesn’t do much more than if you just used the numbers themselves in the foreach statement. However, you can’t—with just numbers—project a new type. With the Lambda Expression, you can project n to a new type with named initialization. For example, changing the Lambda Expression to n⇒ Number=n causes the extension method to project (or create) a new anonymous type with a field Number. By adding a second named type, you could add an additional field that indicates whether the number n is odd or even. Listing 5.15 shows the revision.

Listing 5.15 Projecting a New Type Using Named Compound Initialization Resulting in a New Anonymous Class with Two Fields Number and IsEven

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;

namespace SelectLambda
{
  class Program
  {
    static void Main(string[] args)
    {
      var numbers = new int[]{1,2,3,4,5,6};
      foreach(var result in numbers.Select(n ⇒ new {Number=n, IsEven=n%2==0}))
        Console.WriteLine(result);
      Console.ReadLine();
    }
  }
}

The new anonymous type is shown in the snapshot of ILDASM (see Figure 5.2), clearly showing the projected anonymous type and the two fields Number and IsEven.

FIGURE 5.2 The snapshot from ILDASM shows that by using compound type initialization and named parameters, in effect, a new class with a Number and IsEven properties is created.

Image

Using Where<T> with Lambda Expressions

The Where<T> extension method is employed in scenarios where you would use conditional logic to filter the elements returned in a resultset. Like Select, Where returns an IEnumerable<T>, where T is defined by the type of the result from the Lambda Expression. Listing 5.16 provides an example of Where that looks for words that contain capital D and lowercase e among the array of strings.

Listing 5.16 Using Where<T> to Search for Words with D and e

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;

namespace WhereLambda
{
  class Program
  {
    static void Main(string[] args)
    {
      var words = new string[]{“Drop”, “Dead”, “Fred”};
      IEnumerable<string> hasDAndE =
        words.Where(s ⇒ s.Contains(‘D’) && s.Contains(‘e’));

      foreach(string s in hasDAndE)
        Console.WriteLine(s);
      Console.ReadLine();
    }
  }
}

Using OrderBy<T> with Lambda Expressions

OrderBy<T> is the extension method that supports sorting. OrderBy accepts a Func generic delegate. The Func argument can be expressed with a literal Lambda Expression. Listing 5.17 demonstrates OrderBy, which is used to sort the array of numbers in ascending order. (To sort in descending order, call the OrderByDescending method.)

Listing 5.17 Sorting Is as Easy as Calling the OrderBy or OrderByDescending Method

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;

namespace OrderByLambda
{
  class Program
  {
    static void Main(string[] args)
    {
      var numbers = new int[]
        {1, 3, 5, 7, 9, 2, 4, 6, 8, 10 };
      IEnumerable<int> ordered = numbers.OrderBy(n⇒n);
      foreach(var num in ordered)
        Console.WriteLine(num);
      Console.ReadLine();
    }
  }
}

Compiling Lambda Expressions as Code or Data

Lambda Expressions are either compiled as code or data. When a Lambda Expression is assigned to a variable, field, or delegate, the compiler emits executable IL. For example, num ⇒ num % 2 == 0; emits IL (see Listing 5.18) that is equivalent to a function that accepts an integer, performs division, and compares the remainder with 0. (The Lambda Expression is defined in a function named Test, hence the emitted <Test>b__1’(int32 num) generated name.)

Listing 5.18 The Lambda Expression num ⇒ num % 2 == o Emits the MSIL Listed Here

.method private hidebysig static bool ‘<Test>b__1’(int32 num) cil managed
{
  .custom instance void [mscorlib]System.Runtime.CompilerServices.
→CompilerGeneratedAttribute::.ctor() = ( 01 00 00 00 )
  // Code size       7 (0x7)
  .maxstack 8
  IL_0000: ldarg.0
  IL_0001: ldc.i4.2
  IL_0002: rem
  IL_0003: ldc.i4.0
  IL_0004: ceq
  IL_0006: ret
} // end of method Program::‘<Test>b__1’

If a Lambda Expression is assigned to a variable, field, or parameter whose type is System.Linq.Expressions.Expression<TDelegate>, where TDelegate is a delegate, code that represents an expression tree is emitted (see Listing 5.19). Expression trees are used for LINQ features like LINQ for Data where LINQ queries are converted to T-SQL.

Listing 5.19 A Lambda Expression (in a Function Test2) Assigned to an Instance of Expression<TDelegate> Emits the IL Shown

.method private hidebysig static void  Test2() cil managed
{
  // Code size       93 (0x5d)
  .maxstack  4
  .locals init ([0] class [System.Core]System.Linq.Expressions.ParameterExpression
→CS$0$0000,
          [1] class [System.Core]System.Linq.Expressions.ParameterExpression[]
→CS$0$0001)
  IL_0000: ldtoken    [mscorlib]System.Int32
  IL_0005: call       class [mscorlib]System.Type [mscorlib]System.Type::
→GetTypeFromHandle(valuetype [mscorlib]System.RuntimeTypeHandle)
  IL_000a: ldstr      “num”
  IL_000f: call       class [System.Core]System.Linq.Expressions.
→ParameterExpression [System.Core]System.Linq.Expressions.
→Expression::Parameter(class [mscorlib]System.Type,

string)
  IL_0014: stloc.0
  IL_0015: ldloc.0
  IL_0016: ldc.i4.2
  IL_0017: box        [mscorlib]System.Int32
  IL_001c: ldtoken    [mscorlib]System.Int32
  IL_0021: call       class [mscorlib]System.Type [mscorlib]System.Type::
→GetTypeFromHandle(valuetype [mscorlib]System.RuntimeTypeHandle)
  IL_0026: call       class [System.Core]System.Linq.Expressions.
→ConstantExpression [System.Core]System.Linq.Expressions.
→Expression::Constant(object,

class [mscorlib]System.Type)
  IL_002b: call       class [System.Core]System.Linq.Expressions.BinaryExpression
→[System.Core]System.Linq.Expressions.Expression::Modulo
→(class [System.Core]System.Linq.Expressions.Expression,

class [System.Core]System.Linq.Expressions.Expression)
  IL_0030: ldc.i4.0
  IL_0031: box        [mscorlib]System.Int32
  IL_0036: ldtoken    [mscorlib]System.Int32
  IL_003b: call       class [mscorlib]System.Type
→[mscorlib]System.Type::GetTypeFromHandle(valuetype
→[mscorlib]System.RuntimeTypeHandle)
  IL_0040: call       class [System.Core]System.Linq.Expressions.
→ConstantExpression [System.Core]System.Linq.Expressions.
→Expression::Constant(object,

class [mscorlib]System.Type)
  IL_0045:  call       class [System.Core]System.Linq.Expressions.
→BinaryExpression [System.Core]System.Linq.Expressions.Expression::
→Equal(class [System.Core]System.Linq.Expressions.Expression,

class [System.Core]System.Linq.Expressions.Expression)
  IL_004a: ldc.i4.1
  IL_004b: newarr     [System.Core]System.Linq.Expressions.ParameterExpression
  IL_0050: stloc.1
  IL_0051: ldloc.1
  IL_0052: ldc.i4.0
  IL_0053: ldloc.0
  IL_0054: stelem.ref
  IL_0055: ldloc.1
  IL_0056: call       class [System.Core]System.Linq.Expressions.
→Expression`1<!!0> [System.Core]System.Linq.Expressions.Expression::
→Lambda<class [System.Core]System.Func`2<int32,bool>>
→(class [System.Core]System.Linq.Expressions.Expression,

class [System.Core]System.Linq.Expressions.ParameterExpression[])
  IL_005b: pop
  IL_005c: ret
} // end of method Program::Test2

The expression tree is an in-memory representation of the Lambda Expression. The expression can be compiled and its underlying Lambda Expression can be invoked just like any other Lambda Expression, but, more important, Lambda Expressions can be passed around and transformed by application programming interfaces (APIs) in new ways—for example, LINQ to SQL. The code in Listing 5.20 shows the code used to generate the MSIL in Listings 5.18 and 5.19 and Test2 includes code to explore the expression tree generated.

Listing 5.20 The Code Used to Generate the MSIL in Listings 5.18 and 5.19 and Additional Code to Explore Expression Trees

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Linq.Expressions;

namespace EmitLambda
{
  class Program
  {
    static void Main(string[] args)
    {
      Test();
      Test2();
    }

    static void Test2()
    {
      Expression<Func<int, bool>> exp =
        num ⇒ num % 2 == 0;
      // The MSIL is generated from the statement above
      Console.WriteLine(“Body: {0}”, exp.Body.ToString());
      Console.WriteLine(“Node Type: {0}”, exp.NodeType);
      Console.WriteLine(“Type: {0}”, exp.Type);
      Func<int, bool> lambda = exp.Compile();
      Console.WriteLine(lambda(2));
      Console.ReadLine();
    }

    static void Test()
    {
      Func<int, bool> lambda = num ⇒ num % 2 == 0;
    }
  }
}

The code in Test2 after the Expression definition demonstrates how you can explore the method body, the kind of expression, and argument types. The output from Test2 is shown in Figure 5.3.

FIGURE 5.3 The output from Test2 in Listing 5.20 illustrates how APIs can explore expressions to figure out what the expression represents and how to convert it to another form, like SQL.

Image

Lambda Expressions and Closures

When you declare a variable local to a function, that variable lives in the stack memory space of the declaring scope. So, for example, when the function returns, the local variables are cleaned up with the stack memory for that function. All of this means that if you use a local variable in a Lambda Expression, that local variable would be undefined when the function’s stack is cleaned up. As a precaution, in the event a Lambda Expression is to be returned from a function, and that Lambda Expression depends on a local variable, the compiler creates a Closure (or wrapper class).

A closure is a generated class that includes a field for each local variable used and the Lambda Expression. The value of the local variable(s) is copied to the generated fields to effectively extend the lifetime of the local variables.

If you are familiar with the behavior of stack memory, this explanation makes sense to you. If unfamiliar, don’t worry. The compiler takes care of creating the closure and all of the plumbing is transparent. Listing 5.21 shows a Lambda Expression that uses a local variable and Figure 5.4 shows the MSIL and the generated closure.

FIGURE 5.4 The closure class generated by the compiler is highlighted in the MSIL snapshot; without the local variable toFind (or any local), the closure is not generated.

Image

Listing 5.21 Using the Local Variable toFind Signals the Compiler to Generate a Closure, or Wrapper Class, so toFind Can’t Become Undefined

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;

namespace LambdaClosure
{
  class Program
  {
    static void Main(string[] args)
    {
      UsesClosure();
    }

    static void UsesClosure()
    {
      string toFind = “ed”;
      var words = new string[]{
        “ended”, “friend”, “closed”, “potato”};

      var matches = words.Select(s ⇒ s.Contains(toFind));
      foreach(var str in matches)
        Console.WriteLine(str);
      Console.ReadLine();
    }
  }
}

Currying

The most fun I had describing currying was to a group at the Ann Arbor Day of .NET at Washtenaw Community College in Michigan: “Currying was invented in the 1930s by the mathematician Carlos Santana.” Wikipedia can tell you about the science and math of currying and who is attributed with its invention. (You are encouraged to read the underscoring explanation of currying.) Here, you’ll get a less-scientific explanation.

Currying is a use of Lambda Expressions in which a multistep expression is broken into several Lambda Expressions. Each Lambda Expression is a feeder to the next expression until the last expression provides the solution. This is sort of like a Turing machine. (“Turing Machines” were described by Alan Turing in the 1940s. Turing machines are basically simple computers that can solve any problem theoretically one step at a time, one piece at a time.) Refer to Listing 5.22 for an example.

Listing 5.22 The First Half Is a Multiargument Lambda Expression and the Second Half Shows the Same Behavior Using Currying

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;

namespace LambdaCurry
{
  class Program
  {
    static void Main(string[] args)
    {
      Func<int, int, int> longLambda = (x,y) ⇒ x + y;
      Console.WriteLine(longLambda(3,4));
      Console.ReadLine();

      // currying
      Func<int, Func<int,int>> curry1 = x ⇒ y ⇒ x + y;
      Console.WriteLine(curry1(3)(4));
      Console.ReadLine();
    }
  }
}

In the first half, longLambda accepts two arguments and returns the sum. After the comment // currying, the same behavior is represented by a Lambda Expression that employs currying. The Lambda Expression curry1 accepts a single int argument and returns a second Lambda y ⇒ x + y. The result is that you can call curry1 with the first operand. This first call returns the second Lambda Expression, which you can immediately invoke—using the function call notation (arg) to invoke that Lambda Expression.

Lambda Expressions that employ currying are a little hard to write, and it is even harder to figure out what to do with currying Lambdas. It might be useful to employ currying Lambdas with code generators by chunking up long problems into singular Lambda Expressions that are daisy-chained together. It will be interesting to see what the programming community does with currying.

The important thing to remember is that for each step in a multiargument Lambda Expression, simply chain another argexpression in the sequence; when invoking the curried expression, chain the function call operator with the input arguments (as demonstrated in Listing 5.22).

Summary

Lambda Expressions are fundamentally shorthand notation for anonymous delegates. They are inline functions. Lambda Expressions return instances of anonymous delegates, such as Func<T>, Predicate<T>, and Action<T>. The delegates are useful in extension methods that use functions to perform operations on arrays and other enumerable types.

Generic delegates, extension methods, and Lambda Expressions are an evolutionary step to LINQ. LINQ is a more natural like query language for .NET. LINQ queries use elements that look similar to query languages like SQL and these LINQ keywords are mapped to extension methods. The arguments to LINQ keywords are mapped to inputs to these extension methods, and the inputs are converted to the required type, usually a generic delegate.

This chapter also included discussions on projections, currying, and closures. Hopefully, these concepts will help you explore Lambda Expressions with your peers and find new and creative ways to use them.

..................Content has been hidden....................

You can't read the all page of ebook, please click here login for view all page.
Reset
18.118.12.157