Implementing Higher Order Messages in Ruby

An Envelope Manufacturing Machine

A higher order message is a message that takes another message as an "argument". It defines how that message is forwarded on to one or more objects and how the responses are collated and returned to the sender. How is this actually implemented?

Under the hood, a method for the higher order message creates and returns a new object that represents the higher order message. This object can capture any message, forward that message on to all the elements of the collection and collate the results that they return into a result that is passed back the sender of the higher-order message.

In Ruby, messages are captured by defining a method named "method_missing". "Method_missing" is invoked with the name and parameters of a message received by an object when the object has no explicit method for that message. That means, however, that a little more magic is required to implement higher order messages. Classes inherit a lot of methods from the Object class. These must be undefined so that they can be captured by method_missing. This is easy to do by calling undef_method. There are some methods that shouldn't be undefined: method_missing, of course, and fundamental methods that begin and end with double underscores. Here then is the base class for higher order messages:

class HigherOrderMessage
  def HigherOrderMessage.is_vital(method)
    return method =~ /__(.+)__|method_missing/
  end
    
  for method in instance_methods
    undef_method(method) unless is_vital(method)
  end
    
  def initialize(handler)
    @handler = handler
  end
end

I can then easily implement higher order message types by extending the HigherOrderMessage class and defining method_missing.

"Do" sends the captured message to all elements of a collection and returns nil:

class Do < HigherOrderMessage
  def method_missing(id, *args)
    @handler.each {|e| e.__send__(id,*args)}
    return nil
  end
end

"Where" selects elements of a collection for which the captured message returns true:

class Where < HigherOrderMessage
  def method_missing(id, *args)
    return @handler.select {|e| e.__send__(id,*args)}
  end
end

I can then add these higher order messages to all enumerable objects by adding them to the Enumerable mix-in:

class Enumerable
  def do
    return Do.new(self)
  end
  
  def where
    return Where.new(self)
  end
end

And that's it for the basics. I added more classes for the other higher order messages, and had to chain two higher order message objects to support the having predicate, but nothing more complex than that.

Anybody got any ideas about an equivalent in Java?

Update: The code is available on RubyForge in the Homer project for anybody who wants to play with it.

Copyright © 2005 Nat Pryce. Posted 2005-10-12. Share it.

Comments powered by Disqus