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 at 5:34 PM in Ruby
[Trackback URL for this entry]
