RUBY: DRY up your Enumerations
May 25th, 2007 byUsing Higher Order Messaging to honestly reveal your intentions.
If you had a collection of stooges (@stooges) and you were looking for Mo, would you rather say:
@stooges.select {|s| s.name == 'Mo'}
or
@stooges.that.have.name == 'Mo'
I don’t have to ask you twice, right?
In the first example, the fact that it’s an enumeration overwhelms the intention to find Mo.
In the second example, the most obvious thing is that I want Mo. The fact that @stooges is a collection is obviously not the most important thing. What matters is that I want Mo and example 2 does a much better job of revealing that.
This is not magic. It’s Higher Order Messaging. And trust me, you want it.
I stumbled across HOM on Why’s blog over a year ago. I followed a link from his site to some other site and downloaded ho_enumerable.rb (sorry, I can no longer find the orginal site, but if you know, let me know and I’ll make proper attribution here). I’ve been using HOM with delight ever since.
What is Higher Order Messaging?
Higher order messaging lets you talk to collections in a natural way that reveals instead of conceals your ultimate intentions. Here are more examples.
(To follow along at home, download hom_examples.rb and ho_enumerable.rb).
Given class Stooge:
class Stooge
attr_reader :name, :hair, :habit
def initialize(aRow)
@name = aRow[0]
@hair = aRow[1]
@habit = aRow[2]
end
def baldish?
hair.nil?
end
def muck_with_name
name.gsub!(/y/, 'x')
end
def to_s
"#<Stooge - name:#{name} hair:#{hair} habit:#{habit}>"
end
end
and array STUFF
STUFF = [[ 'Mo', 'bowly', 'eye poking' ],
[ 'Larry', 'curly', 'whomping' ],
[ 'Curly', nil, 'whining' ]]
I can create a new collection of Stooges by saying
@stooges = STUFF.as(Stooge)
instead of
@stooges = STUFF.collect {|r| Stooge.new(r)}
I can select all of the stooges that are nearly bald by saying
@stooges.that.are.baldish?
instead of
@stooges.select {|s| s.baldish?}
I can find all of the stooges named ‘Mo’ by
@stooges.that.have.name == 'Mo'
instead of
@stooges.select {|s| s.name == 'Mo'}
I can build an array of all of their names by saying
@stooges.extract.name
instead of
@stooges.collect {|s| s.name}
I can find out if ‘all’, or ‘any’, stooges ‘are’ or ‘have’ some quality. (Since you’re completely sold now I’m gonna leave the iteration style code to you).
@stooges.all.are.baldish? # false @stooges.any.are.baldish? # true
@stooges.all.are_not.baldish? # false @stooges.any.are_not.baldish? # true
@stooges.all.have.name == 'Mo' # false @stooges.any.have.name == 'Mo' # true
I can also order the stooges by some attribute.
@stooges.in_order_of.name @stooges.in_reverse_order_of.name
And I can perform some operation against every stooge.
@stooges.do.muck_with_name
The ho_enumerable code is very short and delightfully nerdly. You may or may not be interested in looking at it to figure out how it works, but you don’t have to understand the details of implementing HOM to recognize what a great idea this is.
Stick ho_enumerable in your rails/lib directory, require the file and start using HOM. Your code will please you by revealing what it’s doing without drowning you in detail about how it’s doing it. And when your friends have to maintain it, they’ll like you even better than you like yourself.
ps - Thanks to Lori Evans for pouring over the ho_enumerable code with me on the plane on the way home from railsconf. It was more than can possibly be expected of any exhausted human being and she was alarmingly cheerful about it. Thanks.

May 26th, 2007 at 11:49 am
Damn, that’s beautiful. Thanks for sharing!
May 28th, 2007 at 10:46 am
Here’s a slightly different approach. It reads a bit more like plain-vanilla Ruby, but still does away with the distracting block syntax. And not counting ‘end’ statements, it’s 12 lines long. (=
http://pastie.caboo.se/65354
May 29th, 2007 at 3:25 pm
Higher Order Messaging? It may have been Nat Pryce or Stephane Ducasse:
http://nat.truemesh.com/archives/000535.html
May 29th, 2007 at 10:01 pm
Here’s yet another take:
http://pastie.caboo.se/65958
May 30th, 2007 at 4:53 am
Cool examples. :-)
The (Sam/Steve) idea of leveraging the already existing enumerable methods really works. I love the way the code reads when I use ho_enumerable but I always have a problem, initially, of remembering the syntax. Implementing HOM using the method names I’m already familiar with definitely fixes this problem.
The (Sharon) idea of overriding the select/reject methods to take a hash is very interesting. That ‘rails’ like syntax is familiar and intuitive and adds a lot of value.
And thanks, Michael, for the references. Unfortunately, the ho_enumerable code came from somewhere else. Dang.
May 30th, 2007 at 8:39 am
It’s an interesting note that while I’m starting to use Moose::Autobox more and more in my perl code so I can say e.g.
$stooges->grep(sub { $_->name eq ‘Mo’ });
in a case like this you’d probably prefer the traditional prefix form
grep { $_->name eq ‘Mo’ } $stooges
which, to me, demonstrates the intent “find Mo from my list of stooges” even better than the .that.have ruby syntax you describe (albeit the HOM syntax is damn pretty nonetheless).
Also, I don’t think the .as is nearly as clear intent-wise as, say
map { Stooge->new($_) } $stuff;
(you need to acquire the habit of reading $_ as ‘this’ in your head for it to truly flow, but it’s both compact and explicit).
The .all/.any examples are very nice, though I can’t really see why you shouldn’t be able to simply do
@stooges.all.baldish?
or
not @stooges.any.baldish?
(and I can certainly see how to make the perl5 Perl6::Junction module do this, so it should be equally easy in ruby).
As for the .do syntax, I’d again argue that the less OO perl style might be clearer -
$_->muck_with_stooge for @stooges;
but that’s one is -very- much an acquired taste and is a bit debatable.
Has anybody given any thought to providing syntax similar to the perl detached grep/map stuff in ruby in the same way we’ve provided the method-y syntax in perl via autobox? Seems only fair for you guys to steal some of our syntax in return :)
June 4th, 2007 at 9:42 am
See my blog entry in response to this at:
http://snakesgemscoffee.blogspot.com/2007/06/higher-order-messaging.html
Or my pastie here:
http://pastie.caboo.se/67657
June 14th, 2007 at 7:44 pm
Would it not be more clear to define domain-specifc class methods? Instead of:
@stooges.that.are.baldish?
one might instead say, given the presence of the Stooge model in a Rails application, (and assuming a database of Stooges rather than an array in memory)
Stooge.baldish
which would yield a collection of baldish Stooges. This might be a database query, it might be cached, etc.
In this case, the intent is clear, and we are hiding the implementation, whereas with ho_enumerable it is very clear that the implementation for finding the baldish Stooges is that of ho_enumerable, which is unfamilar for a Ruby programmer who has not seen it.
As well, it appears to me to be unobvious how to write new queries using ho_enumerable. (”that.have” or “which.have”?) AppleScript is similar in this regard. It attempts to be “natural”, but when one tries something that seems natural, it often turns out to not be the right kind of natural.
However, I use test/spec, and should.be seems okay to me, so I guess I don’t know.
June 15th, 2007 at 12:25 am
The advantage of using the ‘that.foo’ syntax is you’ve reduced your impact on classes that mix you in. All the magic happens in a couple of methods and the proxy classes they return and not in the extended class’s method_missing.
Big leverage and with low impact on the extended class? That’ll do nicely.
Similar things have happened with RSpec recently, which went from methods like ‘value.should_not_be_nil’ to ‘value.should_not be_nil’ so, instead of having to fight with rails over who got the last go with method_missing, they just install two methods ’should’ and ’should_not’ and they’re done (modulo the magic with the matcher stuff). Result.
June 16th, 2007 at 2:33 pm
It’s a very nice concept, however, the problem I see with this is that it removes natural language from the parts that should be natural language (or at least, “more natural”.
In particular, the dot syntax breaks down quickly when the query has two or more filters. For instance, I don’t think we’d want to say
@stooges.all.are.baldish.and.tubby?Looking at this in SQL against a badly designed (but common enough) model:
SELECT * FROM stooges WHERE hair = 'baldish' AND girth = 'tubby';Even with the unnaturalness of the SQL language, it still seems better (to me) than the dot notation expressed in the article (presuming I understood how you intend to represent junctions).
Matt Trout shows the Perl 5 way (Perl 6 is much different), which is essentially the functional way of map, reduce, filter, and find. These forms are very familiar to rubyists, and have excellent traits when it comes to concurrence.
In languages such as Haskell and Scala, they actually remain pretty readable too. Nevertheless, its possible to consider renaming the operators involved into some sort of more readable form.
Since JavaScript is prototype based, many programmers have built their functional add-ons right into the Array object. So, for instance, you could say
stooges.find(...)That’s still not completing your stylistic goal, but not hard to fix it.
Finally, there is the SPARQL query language for RDF, which neatly solves the rigid model problems of my SQL example above, and yet can be pretty hard to read, or at least don’t fulfill your aims here.
My thought is that perhaps careful elimination of dot notation for junctions and verbs, and maybe using parameter style forms for the filters might get closer.
August 9th, 2007 at 9:10 am
Nah, it was me.
In about 1996 or 1997, I became sick and tired of writing loops (Objective-C does not have blocks) and first came up with enum-filters. These were a bit of an improvement but still not quite there, because they needed an increasing number of variations in order to express the message that would be used to filter the objects.
The conundrum was how to encode fairly arbitrary messages as parameters to another message (the one constructing the enum-filter). The “duh” moment took quite some time to hit me.
Stephane Ducasse collaborated on the paper in 2005 (http://www.metaobject.com/papers/Higher_Order_Messaging_OOPSLA_2005.pdf) and was very helpful in getting that into publishable shape.
Nat Pryce was, I think, the first Ruby developer to pick up and write about HOM.