Extension methods, Lambda expressions and IronPython

Together with extension methods, lambda expressions are the enablers of linq. IronPython (and python) support the notion of lambda expressions. However, there is no direct support for calling Extension methods in IronPython (yet). That is to say, you can call them, but only in their 'static method in static class form', like so:

customers = GetCustomers()
namesOfJohns = Enumerable.Select(\
                   Enumerable.Where(
                    customers, \
                    lambda c : c.Name.StartsWith("John")), \
                lambda c : c.Name);

This works, obviously, but the syntax is hardly readable, you will agree. Not convinced? What about this:

namesOrJohnsOrdered = Enumerable.Select(\
       Enumerable.ThenBy(\
          Enumerable.OrderBy(\
             Enumerable.Where(\
                customers, \
                lambda c : c.Name.StartsWith("John")), \
             lambda c : c.BirthDate), \
          lambda c : c.Name), \
       lambda c : c.Name);

In C#, using the Chained Method syntax, it looks like this:

var namesOfJohnsOrdered = customers
                .Where(c => c.Name.StartsWith("John")
                .OrderBy(c => c.BirthDate)
                .ThenBy(c => c.Name)
                .Select(c => c.Name);

I rest my case :-).

So, what do we want to achieve?

Well, as we saw, Python does have the notion of lambda expressions, so we’d like to reuse those. But can we achieve the chained syntax in IronPython, similar to the C# example above? If we could, it would look like this:

   namesOfJohnsOrdered = customers.\
      .Where(lambda c : c.Name.StartsWith(“John”))\
      .Select(lambda c : c.Name)

How to achieve this?

If you think about it, extension methods are in fact a fancy way to implement the decorator pattern.

The decorator pattern can be used to make it possible to extend (decorate) the functionality of a certain object at runtime, independently of other instances of the same class, provided some groundwork is done at design time. This is achieved by designing a new decorator class that wraps the original class.

What if we wrote a class that extends IEnumerable<T>, with wrapper functions for the all linq operators we want to use? Here's what I have in mind:

public class ToLinq<T> : IEnumerable<T>
{
    private readonly IEnumerable<T> _wrapped;

    public ToLinq(IEnumerable<T> wrapped)
    {
        _wrapped = wrapped;
    }

    public ToLinq<T> Where(Func<T, bool> predicate)
    {
        return new ToLinq<T>(_wrapped.Where(predicate));
    }

    public ToLinq<U> Select<U>(Func<T, U> selector)
    {
        return  new ToLinq<U>(_wrapped.Select(selector));
    }

    public bool Any(Func<T, bool> predicate)
    {
        return _wrapped.Any(predicate);
    }

    public int Count()
    {
        return _wrapped.Count();
    }

    // etc, you get the idea

}

We can use this from IronPython as follows:

import clr
clr.AddReference("ConsoleApplication3")
clr.AddReference("IronPythonLinqBridge")

from IronPythonLinqBridge import *
from ConsoleApplication3 import Customer

def Enumerate(customers) :
    johns = ToLinq[Customer](customers)\
        .Where(lambda c: c.Name.StartsWith("John"))\
        .Select(lambda c: c.Name)
    for name in johns : print name

As you can see, the ToLinq class in IronPython is called like a method. This covers the scenario where we have some .Net code that passes an IEnumerable sequence to IronPython. It also works with standard python sequences.

This script is called from C# code like so:

var engine = Python.CreateEngine();

dynamic enumerator = engine.CreateScope();
engine.Execute(File.ReadAllText("enumerator.py"), enumerator);

var customers = new[]
                    {
                        new Customer {Name = "John Johnson"},
                        new Customer {Name = "Gosse Jordan"},
                        new Customer {Name = "John Donahue"},
                        new Customer {Name = "Andie Reynard"}
                    };
enumerator.Enumerate(customers);