The Beauty of Closures

Filter 1: Matching short strings (length fixed)

Our sample situation is going to be really basic, but I hope you'll be able to see the significance anyway. We'll take a list of strings, and then produce another list which contains only the "short" strings from the original list. Building a list is clearly simple - it's creating the predicate which is the tricky bit.

In C# 1, we have to have a method to represent the logic of our predicate. The delegate instance is then created by specifying the name of the method. (Of course this code isn't actually valid C# 1 due to the use of generics, but concentrate on how the delegate instance is being created - that's the important bit.)

// In Example1a.cs
static void Main()
{
    Predicate<string> predicate = new Predicate<string>(MatchFourLettersOrFewer);
    IList<string> shortWords = ListUtil.Filter(SampleData.Words, predicate);
    ListUtil.Dump(shortWords);
}

static bool MatchFourLettersOrFewer(string item)
{
    return item.Length <= 4;
}

In C# 2, we have three options. We can use exactly the same code as before, or we can simplify it very slightly using the new method group conversions available, or we can use an anonymous method to specify the predicate's logic "inline". The enhanced method group conversion option isn't worth spending very much time on - it's just a case of changing new Predicate(MatchFourLettersOrFewer) to MatchFourLettersOrFewer. It's available in the downloadable code though (in Example1b.cs). The anonymous method option is much more interesting:

static void Main()
{
    Predicate<string> predicate = delegate(string item)
        {
            return item.Length <= 4;
        };
    IList<string> shortWords = ListUtil.Filter(SampleData.Words, predicate);
    ListUtil.Dump(shortWords);
}

We no longer have an extraneous method, and the behaviour of the predicate is obvious at the point of use. Good stuff. How does this work behind the scenes? Well, if you use ildasm or Reflector to look at the generated code, you'll see that it's pretty much the same as the previous example: the compiler has just done some of the work for us. We'll see later on how it's capable of doing a lot more...

In C# 3 you have all the same options as before, but also lambda expressions. For the purposes of this article, lambda expressions are really just anonymous methods in a concise form. (The big difference between the two when it comes to LINQ is that lambda expressions can be converted to expression trees, but that's irrelevant here.) The code looks like this when using a lambda expression:

static void Main()
{
    Predicate<string> predicate = item => item.Length <= 4;
    IList<string> shortWords = ListUtil.Filter(SampleData.Words, predicate);
    ListUtil.Dump(shortWords);
}

Ignore the fact that by using the <= it looks like we've got a big arrow pointing at item.Length - I kept it that way for consistency, but it could equally have been written as Predicate predicate = item => item.Length < 5;

In Java we don't have to create a delegate - we have to implement an interface. The simplest way is to create a new class to implement the interface, like this:

// In FourLetterPredicate.java
public class FourLetterPredicate implements Predicate<String>
{
    public boolean match(String item)
    {
        return item.length() <= 4;
    }
}

// In Example1a.java
public static void main(String[] args)
{
    Predicate<String> predicate = new FourLetterPredicate();
    List<String> shortWords = ListUtil.filter(SampleData.WORDS, predicate);
    ListUtil.dump(shortWords);
}

That doesn't use any fancy language features, but it does involve a whole separate class just to express one small piece of logic. Following Java conventions, the class is likely to be in a different file, making it harder to read the code which is using it. We could make it a nested class instead, but the logic is still away from the code which uses it - it's a more verbose version of the C# 1 solution, effectively. (Again, I won't show the nested class version here, but it's in the downloadable code as Example1b.java.) Java does allow the code to be expressed inline, however, using anonymous classes. Here's the code in all its glory:

// In Example 1c.java
public static void main(String[] args)
{
    Predicate<String> predicate = new Predicate<String>()
    {
        public boolean match(String item)
        {
            return item.length() <= 4;
        }
    };

    List<String> shortWords = ListUtil.filter(SampleData.WORDS, predicate);
    ListUtil.dump(shortWords);
}

As you can see, there's a lot of syntactic noise here compared with the C# 2 and 3 solutions, but at least the code is visible in the right place. This is Java's current support for closures... which leads us nicely into the second example.

You might also like...

Comments

About the author

Jon Skeet United Kingdom

C# MVP currently living in Reading and working for Google.

Interested in writing for us? Find out more.

Contribute

Why not write for us? Or you could submit an event or a user group in your area. Alternatively just tell us what you think!

Our tools

We've got automatic conversion tools to convert C# to VB.NET, VB.NET to C#. Also you can compress javascript and compress css and generate sql connection strings.

“Better train people and risk they leave – than do nothing and risk they stay.” - Anonymous