Image a Ruby where if/then/else isn’t available:

1 class Account
2   # This method returns the balance in words, negative or positive, ready for display in the UI
3   def balance_in_words
4     # Err...  How do I do that?
5   end
6 end

If you were a strict Object-Oriented person, you’d do it this way:

 1 class PositiveBalanceAccount
 2   def balance_in_words
 3     "Positive"
 4   end
 5 end
 6 
 7 class NegativeBalanceAccount
 8   def balance_in_words
 9     "Negative"
10   end
11 end

But then, your objects would have to change class whily-nilly. Pretty darn hard. But multi-method dispatching gives us a nice solution:

 1 class Account
 2   def initialize(balance)
 3     @balance = balance
 4   end
 5 
 6   defmulti :balance_in_words,
 7     lambda { @balance < 0 } => "Negative",
 8     lambda { @balance > 0 } => "Positive"
 9 end
10 
11 Account.new(15).balance_in_words # => "Positive"
12 Account.new(-5).balance_in_words # => "Negative"

For the observant amongst you, you might have noticed I forgot the nil balance case. This is really a programming error, so it should be treated as such:

1 Account.new(0).balance_in_words
2 lib/defmulti.rb:46:in `balance_in_words': #<Account:0x197222c @balance=0> received balance_in_words but did not have a guard clause that matched and no else clause. (Defmulti::MissingGuardClause)
3         from test.rb:16
4 

For the even more observant, yes, there exists an implementation that does exactly what I have described above. It’s called defmulti, it’s a gem, and it’s on GitHub: http://github.com/francois/defmulti.

What is this useful for?

This library is a thought experiment. When you lose the familiar tools, what can you do? Of course, this library works atop the existing Ruby implementation and to be truly useful, syntax would have to be provided to make this much less verbose. It’s interesting nonetheless to see what can be done without the syntax extensions.

Anyway, what would you use this for? Multi-method dispatching is a tool that helps writing code without conditionals. The conditionals are specified outside the block of code that executes. The examples above are pretty thin, but looking at Java.next #3: Dispatch, I can provide another solution to his Ruby example:

 1 defmulti :letter_grade,
 2   lambda {|grade| (90..100).include?(grade) || grade == "A"} => "A",
 3   lambda {|grade| (80...90).include?(grade) || grade == "B"} => "B",
 4   lambda {|grade| (70...80).include?(grade) || grade == "C"} => "C",
 5   lambda {|grade| (60...70).include?(grade) || grade == "D"} => "D",
 6   lambda {|grade| ( 0...60).include?(grade) || grade == "F"} => "F"
 7 
 8 letter_grade 60  # => "D"
 9 letter_grade "A" # => "A"
10 letter_grade nil # => Defmulti::MissingGuardClause

Again, I’m struck by the clunky syntax, but if we ignore that for a second, could this be even better than Stuart Halloway’s example? Ruby’s case statement is very, very powerful and very easy to use. Is this useful? Not at the moment. But it’s a thought experiment I thought I’d throw out there.

Search

Your Host

A picture of me

I am François Beausoleil, a Ruby on Rails and Scala developer. During the day, I work on Seevibes, a platform to measure social interactions related to TV shows. At night, I am interested many things. Read my biography.

Top Tags

Books I read and recommend

Links

Projects I work on

Projects I worked on