Bookmark and Share

Lambdas for Junior Developers

I spoke with someone today who disallows the use of lambdas for his team. His reasoning is that code must be maintainable, and developers with two years experience don’t understand lambdas. I completely agree with the first point, but I disagree that lambdas make code unmaintainable. Understanding how to use lambdas is easily within the grasp of any C# developer.

First, I will define a TreeNode class with a simple find method.

public class TreeNode
{
    private List<TreeNode> children = new List<TreeNode>();

    public IEnumerable<TreeNode> Children
    {
        get { return children; }
    }

    public string Text { get; set; }

    public TreeNode(string text)
    {
        this.Text = text;
    }

    public TreeNode Find(Func<TreeNode, bool> predicate)
    {
        if (predicate(this))
        {
            return this;
        }

        foreach (TreeNode node in children)
        {
            TreeNode found = node.Find(predicate);
            if (found != null)
            {
                return found;
            }
        }

        return null;
    }

    public TreeNode With(TreeNode node)
    {
        children.Add(node);
        return this;
    }

    public TreeNode With(IEnumerable<TreeNode> nodes)
    {
        children.AddRange(nodes);
        return this;
    }

}

This allows for a basic tree structure, and it includes a Find method that accepts a lambda argument. I am going to build a test to show how this class works.

[TestMethod]
public void ShouldFindNode()
{
    var tree = new TreeNode("first").With(new TreeNode("second").With(new TreeNode("third")))
                                    .With(new TreeNode("fourth"))
                                    .With(new TreeNode("fifth").With(new TreeNode("sixth")));

    TreeNode found = tree.Find(node => node.Text.StartsWith("t"));

    Assert.AreEqual("third", found.Text);
}

I’ve constructed the tree using the With method. It’s laid out in a manner where the tree can be easily visualized: the first node has three child nodes, and two of those nodes contains a node. Interpreting the usage of the Find method is fairly straightforward. It will find a node whose Text property starts with ‘t’.

To figure out how this works, it is important to look at the method signature of Find.

public TreeNode Find(Func<TreeNode, bool> predicate)

The argument to this method is a lambda, but its parameter is a Func<TreeNode, Bool>. Using lambdas to create a Func is the most common scenario encountered when utilizing a class library.

This particular Func has two generic parameters defined within the angle brackets. The Func classes defined in the .NET Framework will always have at least one generic parameter, as the last parameter must be its return type. The rest of the generic parameters are the types of arguments the Func will accept. Func is basically a method that can be referred to as an object, meaning it can be passed around.

In this particular example, We’ve used a Func<TreeNode, bool>. This means it will have one argument of type TreeNode and it returns a bool.

The parameter was named predicate. Analyzing the usage of this parameter reveals how Func classes operate.

if (predicate(this))
{
    return this;
}

The predicate is accepting the current TreeNode, this, and it returns true or false. If it was true, then the Find method has found the node and it returns it.

The easiest way to pass the Func<TreeNode, bool> argument is with a lambda to define it.

TreeNode found = tree.Find(node => node.Text.StartsWith("t"));

The most confusing part to someone reading this syntax for the first time is the lambda operator: =>. This can be translated to “goes into.” When creating a Func of any type, the parameters must be given a name on the left, so they can be used on the right. As long as it’s a valid identifier, you can use any name. I named the parameter node, since it’s a TreeNode, but oftentimes the lambda variable is represented with a single letter.

TreeNode found = tree.Find(n => n.Text.StartsWith("t"));

The right side contains a call to StartsWith, which returns a Boolean value. This makes the lambda match up perfectly with a Func<TreeNode, bool> which the Find method accepts as an argument. Multiple lambda variable names must be wrapped in parentheses. For example, a Func<int, int, int> could be defined as (a, b) => a + b;

You may be wondering why you would create this type of Find method rather than one that accepts a string as an argument. The reason is quite simple: Find(string text) limits the caller of the method to only search the node’s text, whereas the lambda can interrogate any condition. If the nodes were richer than example, other properties could be analyzed. Even within the context of checking the node text, more flexibility is inherent in this signature.

TreeNode found = tree.Find(node => node.Text.StartsWith("f") && node.Text.EndsWith("fth"));

Assert.AreEqual("fifth", found.Text);

Lambdas are deeper than what is presented here, but this covers the primary use case encountered while developing software. Once this concept is grasped and the benefits are realized, lambdas become second nature to C# developers just like many other language features.

Here are a few exercises that can help you familiarize yourself with lambdas and take it to the next level.

  1. Create a method with this signature: string Find(Func<string, bool> predicate).
  2. Create a method with signature: string MakeString(Func<int, string> func).
  3. Fill in the missing blank: Func<int, int> addOne = [YourCode].
  4. Fill in the missing blank: Func<int, int, int> multiply = [YourCode].
  5. Create a method with this signature: void Execute(Action<string> action).
  6. Create a method with this signature: bool Evaluate(Func<int> func).
blog comments powered by Disqus

KodefuGuru.GetInfo()

Chris Eargle
LinkedIn Twitter Technorati Facebook

Chris Eargle
Telerik Developer Evangelist, C# MVP

JustCode

Telerik .NET Ninja

 

INETA Community Speakers Program

 

MVP - Visual C#

 

Friend of RedGate

World Map

Month List

Disclaimer

The opinions expressed herein are my own personal opinions and do not represent my employer's view in any way.

© Copyright 2010
Disclaimer: The opinions expressed herein are my own personal opinions and do not represent my employer’s view in any way.