Querying and Enumeration

Querying a collection is interesting in that, basically, all the operations are built on enumeration. Filtering an array? Enumerate it, and reject elements that don’t meet the predicate. Transforming an array? Enumerate it, and apply the transformation function to each element. Reducing an array (e.g., summing up its elements)? Enumerate it, and keep a running total as you add up each element. That means that, if the language and library desingers were clever, just having enumeration on a class is enough to make it queryable with the full filter/map/reduce set of array operations. This means that, in many languages, it’ possible to write custom collections that add a lot of functionality just by implementing enumeration on our class.

Today we’re going to write two classes, Menu and MenuItem, in both C# and Ruby, and look at how we can tell the code to treat Menu as a collection of MenuItems and then query it. (Also, this post was inspired by another)

In C#, we’re going to use LINQ (the strangely named Language-Integrated Query library that gives C# map/reduce like functionality), and we’ll use the Ruby module Enumerable. Both programs will do the same thing: Look at a list of menu items and filter them based on allergen information. Let’s start with C#.

To get a class in C# to work with LINQ, we have to implement the IEnumerable<T> interface. The C# interface IEnumerable<T> just exposes one public method: GetEnumerator(). There’s one historical accident that, in my estimation, mars otherwise very clean implementation: To implement IEnumerable<T>, we have to implement IEnumerable. In other words, because the non-type-safe IEnumerable was around before the type-safe IEnumerable, we need to use both. Here’s the implementation:

On line 8, we declare that we want this class to be enumerable. Then on line 17, we implement a very simple enumerator. In this case, we just return the enumerator of the underlying list. Line 22 is the blemish I alluded to earlier: because C# 1.0 didn’t have generics, parts of the language rely on the IEnumerable interface, rather than on the IEnumerable<T> interface, so we have to implement both. In this case, we can just return the same enumerator in response to both methods. (The difference is that clients calling the second method will see a collection of Object, not a collection of MenuItem, and will have to cast at runtime.)

That let’s us make this happy little snippet:

var okToEat = menu
              .Where(item => !item.Allergens.Contains("shellfish"))

Now let’s look at the same thing in Ruby:

This essentially the same class. The important line is line 2: include Enumerable. This adds Ruby’s Enumerable module into the class, which keeps us from getting NoMethoErrors if we call each or filter. Consuming this ruby class looks like this:

ok_to_eat = menu.reject { |item| item.allergens.include? 'shellfish' }

It’s also worth noting that both Ruby and C# will now let you use a Menu in a regular for each loop. I think this can be a handy, if little-used feature in both languages. Here are some reasons why you would do this:

  1. You need to represent an object in your business domain that logically is a collection of some kind.
  2. You want to implement a data structure that didn’t come with the base class libraries, and you want to be able to enumerate that data structure.
  3. You want to make a data structure that clients can query but cannot modify.

I also want to point out some interesting similarities: First, even though Ruby and C# are very different languages, they’ve both constructed enumeration and querying collections in such a way that it can be achieved in user-defined classes just by implementing one method: GetEnumerator() in C# and #each in Ruby. They have also both implemented their native for each loops in such a way that user-defined collections can be used in them. So thanks, language designers for this cool thing.

Till next time, happy learning!


Acknowledgments: A few things gave me the idea for this post: First, in an episode of .NET Rocks, though I can’t find the specific episode, Carl said simply, “If you can enumerate a collection you can query it.” Second, I went to a Meetup talk in DC where the speaker ran through a number of different programs that can be written in JavaScript using only map, filer, and reduce. Also, I should thank Jon Skeet for writing the excellent C# in Depth, without which I would not understand C# well enought to write posts like this.

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out /  Change )

Google photo

You are commenting using your Google account. Log Out /  Change )

Twitter picture

You are commenting using your Twitter account. Log Out /  Change )

Facebook photo

You are commenting using your Facebook account. Log Out /  Change )

Connecting to %s