The Blog

21 Dec 2005: Recent changes

Yield

Supporting yield was harder than it first seemed. The problem was that Nemerle already supports most of the stuff needed for yield (for example putting local variables in classes so they persist), but unfortunately in a slightly different way, so a reimplementation was required in a few cases. This was very irritating (as doing the same thing twice always is). Fortunately now it works.

There was another problem with finally blocks which has to be run only once (we don't want finally blocks to be run, when yielding a value from inside try), and also when the iterator is prematurely disposed. Fortunately C# doesn't allow yield in try-catch, so we decided to do the same ;)

The C# spec was quite sketchy about this issue though.

List comprehensions

Haskell (as well as Python to some extent) has this really nice nice notation, that comes from math. The idea is to describe a set in terms of all such x that x comes from the set A and is greater than zero. This would be written as:

$ [ x | x in A, x > 0 ]

But this isn't really funny, so let's look at something more complicated, all such pairs (x, y) that x comes from A and y comes from B:

$ [ (x, y) | x in A, y in B ]

We can now further restrict this to x < y:

$ [ (x, y) | x in A, y in B, x < y ]

We can even apply some complex expressions, for example to return set of lengths of elements in A we would use:

$ [ x.Length | x in A ]

There are functions to do all that stuff in Nemerle standard library, but list comprehensions provide a way to combine them in one short expressions. The translation of this stuff to the underling core language is straightforward -- each e in something is translated to a nested foreach loop and each condition is translated to when, details are here.

For example to list all members in all types in all assemblies used by the program one could use:

def allMembers = $[m | a in System.AppDomain.CurrentDomain.GetAssemblies (), t in a.GetTypes (), m in t.GetMembers ()];

To limit this to types from the "System" namespace we could use:

def systemMembers = $[m | a in System.AppDomain.CurrentDomain.GetAssemblies (), t in a.GetTypes (), t.Namespace == "System", m in t.GetMembers ()];

And so on. Note that the following statement would have similar effect:

def systemMembers = $[m | a in System.AppDomain.CurrentDomain.GetAssemblies (), t in a.GetTypes (), m in t.GetMembers (), t.Namespace == "System"];

But it would be less efficient because of calling GetMembers even for types outside System, and only discarding them later.

This is really a nice feature and only one hour to implement :-)

What should come next is something like:

$[(x,y) | x in [1...3], y in [1,3,...,15]]