September 15, 2007

The Ternary/AndAnd Destroyer

Filed under: ruby — Tags: — coderrr @ 6:59 pm

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

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

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 _?

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

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.


  1. […] 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

  2. […] 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

  3. 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

  4. 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

  5. […] 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

RSS feed for comments on this post. TrackBack URI

Leave a Reply

Please log in using one of these methods to post your comment: Logo

You are commenting using your account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s

The Silver is the New Black Theme. Create a free website or blog at


Get every new post delivered to your Inbox.

Join 31 other followers

%d bloggers like this: