Quiz
Posted by
Tom | August 25, 2007 13 Responses comments

This neat hack just popped into my head — something I’ve wanted for ages. But what is it for?

    class Object
      def _?()
        self
      end
    end

    class NilClass
      def _?()
        SafeNil.new
      end
    end

    class SafeNil
      def method_missing(*args, &b)
        nil.send(*args, &b) rescue nil
      end
    end

Reader Comments Add your comment »

stringornil._?.length

Cute. Suggestion:

class SafeNil
  def method_missing(*args, &b)
    nil.send(*args, &b) rescue SafeNil.new
  end
end

Then

stringornil._?.length * 4

I call mine null:

class Object
def null
n = Object.new
def null.method_missing(name, *args)
null
end
n
end
end

(stringornil||null).length * 4

best,
Dan

[…] Tom Locke and I have similar proclivities. He says: […]

Nice extra trick Daniel. For my money I think I’d rather not have those SafeNil objects floating around my app who knows where.

The usage pattern is that you always call a method directly on the ._?. If you follow that, the SafeNil object is never seen.

You’re right, and my suggested change is wrong, because you need the resulting object to evaluate as false in case it is used as a condition.

AFAIK there’s no way to make an arbitrary object evaluate to false in Ruby. Maybe that would be an interesting Ruby 1.9 extension:

class A
include Falseness
end

then instances of A would evaluate to false in ‘if’ statements.

Interesting idea. I think Python has user-defined ‘truthness’ along these lines.

Good in loose views for missing methods? I dunno. SafeNil makes me nervous…

Awesome! very useful!

2000% speed increase if you define SafeNil this way:

class SafeNil
  def method_missing(method, *args, &b)
    return nil  unless nil.respond_to? method
    nil.send(method, *args, &b) rescue nil
  end
end

Only problem with this way would be if you define methodmissing on nil to route method calls to it, because then respondto? wouldn’t be accurate

[…] The Ternary Destroyer Filed under: Uncategorized — 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 operator. […]

Why not just use single-line conditionals?

x = string_or_nil.length unless string_or_nil.nil?
x #=> nil

Or, if you’re looking for compound conditions:

if (not string_or_nil.nil?) && (string_or_nil.length == 4)

This seems like a fair bit of cleverness to avoid making your guard conditions explicit — which seems to me like it could make maintenance more of a pain than it already is.

Also, unlike the ternary operator, this doesn’t allow you to specify a fallback value without using || or some other comparison. Why not this:

x = (string_or_nil && string_or_nil.length) || 6

Other than that, cool Ruby trick.

Coda — all of your examples have one thing in commen that this operator was specifically intended to avoid. string_or_nil occurs twice.

The places where I use _? are where I don’t have the value in a local variable, and I don’t want to assign it to one just because I have an operation to perform “only if the value is not nil”. e.g.

if Foo.expensive_method_call._?.closed?
  ...

I see this pattern all the time in my code and I really enjoy not having to make the code more verbose. To me this reads like a spec, once you’ve internalised the simple _? operator.

This is awesome! I’ve been wanting something like this for ages.

I hope you don’t mind, I’ve added it to the quality_extensions gem on RubyForge. (rdoc source)

Hopefully we can get this included in Facets too so an even wider group of people can enjoy it!

[…] Monkey-patching proposals have abounded in the Ruby community recently - including, but not limited to Object#andand, Object#? and SafeNil and Object#method. […]


Write a Comment

Comments are formatted using markdown. To include code, either quote it in `backticks` or indent a code-block by 4 spaces.