I just ran across this Hobo blog post which describes an awesome way to get rid of a lot of use cases for the ternary or && operator.
A lot of the time I end up doing stuff like Something.something_else[:huh] ? Something.something_else[:huh].do_stuff : nil or Something.something_else[:huh] && Something.something_else[:huh].do_stuff and if I’m worried about how long it takes to evaluate Something.something_else[:huh] I’ll even go so far to make it (s = Something.something_else[:huh]) && s.do_stuff. Very ugly indeed. Now with this new operator we can just do: Something.something_else[:huh]._?.do_stuff. It’s so cool!
What it does is define the method _? on Object which just returns self and define _? on nil which returns a proxy object that returns nil if you try to call any method on it which doesn’t exist on nil (instead of raising an exception). And if the method does exist on nil it will pass the method call through to it.
The way Hobo wrote the proxy object was like this:
class SafeNil
def method_missing(*args, &b)
nil.send(*args, &b) rescue nil
end
end
I knew that rescue blocks are slow in general. So I made this optimization and saw a 2000% increase in speed:
class SafeNil
def method_missing(method, *args, &b)
return nil unless nil.respond_to? method
nil.send(method, *args, &b) rescue nil
end
end
We can also optimize a little more and get another 2x speed increase. Instead of instantiating a new SafeNil object every time we you call ._? on nil we can always return the same object. There’s a lot of different ways to do this, I just used the singleton pattern:
class NilClass
def _?
SafeNil.instance
end
end
class SafeNil < BasicObject
include Singleton
undef inspect
def method_missing(method, *args, &b)
return nil unless nil.respond_to? method
nil.send(method, *args, &b) rescue nil
end
end
The only time when you won’t want to use my version is if you indulge in metahaxxing the nil object with method_missing because respond_to? will not be accurate if you use method_missing to route method calls.
I used the ‘facets’ library’s BasicObject because it provides us with a clean slate. It is similar to Object except it has almost all the standard methods stripped away so that we will hit method_missing for almost all method routing.

[...] people behind andand, try, do_or_do_not, NilClass#method_missing, SafeNil, maybe, etc. seem to be trying to beautifully solve the problem of calling methods on objects that [...]
Pingback by Ruby, a message to you » You might be able to stop trying to call methods on nil — March 4, 2008 @ 5:15 pm
[...] new method in Ruby 1.9 is making some people happy and creative too. The only problem with that in my opinion is that every one is fixed about using method chaining [...]
Pingback by A better “try()” for Ruby, why not do the Groovy way? | Urubatan’s Weblog — March 6, 2008 @ 5:42 pm
You’re better off taking the speed hit in your last example to allow the meta programming to work. With only accessing it through ._? it wont be much of an issue anyway.
Comment by Steven Soroka — July 8, 2008 @ 4:19 pm
Steven,
Sorry I don’t understand your comment “to allow the meta programming to work”. Can you elaborate?
Comment by coderrr — July 8, 2008 @ 6:35 pm
[...] I came across a few other alternatives that were entertaining the idea of using method_missing, but let’s [...]
Pingback by Try() as you might | Lambda @ Copa — January 11, 2009 @ 12:44 pm