Updated 1 February 2014 to add the section on
At my last job, I was doing C#/.NET development. I prefer open to proprietary platforms, but I will say that C# is a great language to work in, and its runtime library has a lot of solid conveniences. One aspect of C# I got hooked on was its robust collections library with vast sets of functional methods to manipulate them. Technically I’m talking about a subset of LINQ, and I’ll narrow the scope of this post to just the regular method or “fluent” syntax, not the special query syntax.
In my current job, I’m mostly working in Vala, whose syntax is modeled on C#’s. There’s a library called libgee (I assume the name is a jab at GLib) that provides Vala with some collections. Libgee is a great start, but it falls short of the convenience of C#’s collections. I don’t want to imply that C# with LINQ is the only way to do collections, but I believe it’s fair to compare Vala and C# here, since Vala is explicit about being modeled after C#.
Where C# has
IEnumerable and a lot of extension methods, libgee
Gee.Traversable is a more recent addition that adds a few LINQ-like
functional methods to its
Gee.Iterables… and oddly enough, its
Gee.Iterators too: they both implement the
Gee.Traversable interface. On
the plus side,
Gee.Traversable lazily evaluates the results of its operations
just like the LINQ methods, but there are two big problems that make it a pain
Gee.Traversableonly adds a few very basic operations. Since Vala doesn’t support extension methods, you’re stuck reimplementing your own
min(), etc. everywhere you need to call it. Libgee can’t be faulted for Vala’s shortcomings, but it could acknowledge them and go the extra mile for the sake of convenience and DRY.
Gee.Traversable’s methods all return
Gee.Iterators, which are cumbersome to work with. It’s awkward to manipulate an object that gives you access to one item at a time from a collection, rather than just looking at the collection itself. For example, you can’t pass a
@foreach()method to get around this problem, but passing a lambda that requires an explicit return is awful compared to a simple loop, especially considering how Vala compiles down to C code and what that means for your stack traces. Compare these contrived examples:
It should be clear now why
Gee.Iterator also implements
you can chain multiple
Gee.Traversable method calls together. I posit that
it would be far less awkward for
Gee.Traversable’s methods to simply return
Gee.Iterables, and let
Gee.Iterator just deal with iteration.
Anyway, these issues have been slowly and steadily grating on my nerves the
whole time I’ve been working on Geary. Recently, I finally set out to
implement a fix. My solution,
Geary.Iterable, is viewable in this
gist. I’ll discuss it in more depth below, but first some examples:
See this commit for more examples from my initial, “lowest hanging fruit” pass over the Geary code. You should already be able to see how useful this new code is.
The bulk of this API is the
Geary.Iterable class, a lightweight wrapper
around a single
Gee.Iterator instance. It implements a similar interface to
Gee.Traversable, each method calling into the wrapped
Geary.Iterable that wraps the result.
Geary.Iterable also implements a Vala-iterable interface, by which I mean it
has a method called
iterator() that returns an object with methods
get(). That’s all Vala needs to be able to use it in
This gets around the problems above by 1) providing a single place to implement
whatever methods might be needed by Geary that aren’t already in
Gee.Traversable, and 2) allowing access to whole collections from results,
including being able to iterate over them in the standard Vala way. And it
adds a minimum of overhead on top of libgee in the process.
IEnumerable, you’re only allowed one iteration on each
Geary.Iterable instance, so there are lots of methods to capture the results
in all kinds of libgee collections when you need to do something more than just
Geary.traverse() convenience function lets you easily break out of a
Gee.Iterable into a
Geary.Iterable. If you need to go the opposite
direction, you can use
to_gee_iterable(), which returns a simple
Gee.Iterable out of a
Update: I later added
convenience functions to convert a static list or an array into a
Geary.Iterable. For example, since Vala lacks C#’s collection initializer
syntax, this is the easiest way that I’ve found to
make a quick single-item
It’s been a few weeks since this landed in Geary, and so far I’ve been quite pleased with how useful it is. I haven’t had time to implement much new code to take full advantage of it, but it’s already come in handy enough that I kick myself for not doing this sooner. You also may have noticed that I didn’t implement the full set of LINQ methods in it. More will come with time, as I need them.
The only downside that I’ve encountered using it is more a fault of Vala’s: there’s no generic parameter inference in Vala, so all the necessary angle brackets make things more verbose than I’d like. Take this example from Geary’s source:
If Vala was better about inferring generic types, that might start to look like a simple one-liner. Regardless, I still highly recommend implementing something like this in your own Vala projects.