Wednesday, 1 April 2009

Ruby Essence vs Ceremony

Last week at DevWeek Tim Ewald and I tried to show some of the elegance of Ruby and I'd like to try and repeat that example here.

We started with a Lion class in honour of the news story that week about "Christian the Lion" (hey, look it up yourselves!). The class is very simple

class Lion

  attr_accessor :message, :name

  def speak
    @message
  end

  def to_s
    "#{self.name} says #{self.message}"
  end

  @@lions = {}

  def self.create message, name
    if @@lions[name] == nil
      @@lions[name] = Lion.new(message, name)
    end
    return @@Lions[name]
  end

  def initialize(message, name)
    @message = message
    @name = name
  end

end

The bit we care about is the self.create method. The idea here is that we provide a function to only allow the creation of one lion with any given name (this was a demo so it didn't need to make sense). To do this there is a class level dictionary (a static) in which to store new lions. We only add lions to this dictionary if they are unique, otherwise we return an existing lion. The code as it is written is not very Ruby-ish, it reads more like C++, C# or Java code than Ruby and that's what I'd like to change.

The first step is to remove the 'return' keyword. In Ruby the last statement in a method is the return value so we can change the code to look like this:

def self.create message, name
  if @@lions[name] == nil
    @@lions[name] = Lion.new(message, name)
  end
  @@Lions[name]
end

The 'if' statement isn't very idiomatic either and in Ruby this can be reduced to

def self.create message, name
  @@lions[name] = Lion.new(message, name) if @@lions[name] == nil 
  @@lions[name]
end

We're still not quite there though. Ruby (like C#) has a 'null co-alescing' operator, which lets me say "if 'x' is not null, use it, else do 'y'", and I can rewrite the above 'if' using this operator (|| in Ruby). It also means I can do away with the final return statement

def self.create message, name
  @@lions[name] || @@lions[name] = Lion.new(message, name)
end

Which says, if @@lions[name] is not null return the value, else assign Lion.new to @@lions[name] and return that value

One line to do what it would take four lines to do in other languages and no keywords. As my friend Stu Halloway would put it, essence over ceremony!

Posted by kevin at 5:34 PM in Ruby

 

[Trackback URL for this entry]

Your comment:

SCode: (*) Generate another code
SCode

Please enter the code as seen in the image above to post your comment.

(not displayed)
 
 
 

Live Comment Preview:

 
« April »
SunMonTueWedThuFriSat
   1234
567891011
12131415161718
19202122232425
2627282930