Emulating Smalltalk's Conditionals in Ruby
If you follow my blog, you know that I enjoy emulating language features from other languages (like Python) in pure-Ruby. On the flight back from London, I read through Smalltalk Best Practice Patterns, and was reminded that Smalltalk doesn't have built-in conditionals.
Instead, they use method calls (aka message sends) to do the heavy lifting:
anObject isNil
ifTrue: [ Transcript show: 'true'. ]
ifFalse: [ Transcript show: 'false'. ].
In contrast, the typical way to do that in Ruby is:
if an_object.nil?
puts "true"
else
puts "false"
end
However, the Smalltalk approach is fully compatible with Ruby's pure-OO approach (which is, in fact, inherited from Smalltalk in the first place). So why not be able to do:
(an_object.nil?).
if_true { puts "true" }.
if_false { puts "false" }
In Ruby, unlike Smalltalk, message sends use a ".", so we need to use periods between the message sends to link them together. With that exception, the semantics of the two languages are roughly identical. And, as usual, the implementation in Ruby is pretty straight-forward:
class Object
def if_true
yield
self
end
def if_false
self
end
end
class NilClass
def if_true
self
end
def if_false
yield
self
end
end
class FalseClass
def if_true
self
end
def if_false
yield
self
end
end
In Ruby, false and nil are "falsy", while all other values are "truthy". Since everything in Ruby inherits from Object, we can simply define if_true and if_false on Object, FalseClass, and NilClass. If the block should be called (if_true on truthy values, or if_false on falsy values), we yield. In all cases, we return "self" so that we can chain if_true to if_false. And that's it.
Of course, this means extending core classes, which some people are shy about doing, but it does mirror the semantics of Smalltalk.