The 28 Bytes of Ruby Joy will notably clean up your code:
All it does is patching the
nil object that it also returns
nil when you call an unknown method on it. Normally it would raise a
NoMethodError. This is the cleaner, non-golfed version:
class NilClass def method_missing *_ nil end end
Consider the following, common situation: You have an instance variable, which usually contains a hash of objects:
@some_hash. Now you want to access
:some_key and want to do something with the value. You also know,
@some_hash is sometimes
nil. So you might want to write
if @some_hash[:some_key] # good looking version # do something with @some_hash[:some_key] end
but it is not working properly, because it fails on when
nil. Instead, you have to write
if @some_hash && @some_hash[:some_key] # correct version # do something with @some_hash[:some_key] end
And this is just an easy example. Let’s take a look at
if @some_hash[:some_key].to_formatted_array # good looking version # do something end
if @some_hash && some_hash[:some_key] && @some_hash[:some_key].to_formatted_array && @some_hash[:some_key].to_formatted_array # correct version # do something end
The 28 Bytes of Ruby Joy allow you to do use the good looking version in both examples.
A drawback of the hack might be, that the application does not crash at some occasions, where it probably should do so, but forwards the
nil. But I think, in reality, this means just a few more tests.
The primary reason, I dislike the exception raising of
nil is that it creates some kind of redundancy. I do not want to double-check if something is
nil. And to say it with the words of Yukihiro Matsumoto himself: “When information is duplicated, the cost of maintaining consistency can be quite high.”
So, what is a strong counter-argument for not using the 28 Bytes of Ruby Joy?
After reading some feedback, I have realised, that I need to add this disclaimer: Don’t just use this hack, if you don’t see all of its consequences – especially when used together with already existing code that assumes the usual
nil exception way (like Ruby on Rails).
However, if you do fully understand it, it might be a nice help on your own projects (maybe in a more decent form).
Here are some more resources about (and arguments against) the topic:
- Paolo “Nusco” Perrotta wrote a nice and detailed explanation about this technique for the PragProg Magazine
- FailFast – a general approach to early get to know when something does not work as it should
- A very interesting article by Reg Braithwaite about why you should not use this technique
- Another way of applying this partly by coderr
- tie-racks opinion: do not write one liners
This is a nice snippet by Yohan to decently activate this feature when needed.
# Egocentric nil # code by Yohan, slightly edited and comments by me # start ego mode block, usage: # catch_nil do # if @some_hash[:some_key].to_formatted_array # # do something # end # end def catch_nil(&block) # grip methods ori_method_missing = NilClass.instance_method(:method_missing) catch_method_missing = NilClass.instance_method(:catch_method_missing) # activate ego mode NilClass.send :define_method, :method_missing, catch_method_missing # run code yield ensure # no matter what happens: restore default nil behaviour NilClass.send :define_method, :method_missing, ori_method_missing end #alias :egonil :catch_nil # ;) # this is the ego nil class NilClass def catch_method_missing(m, *args, &block) nil end end
This version does not use method_missing and allows a default value (but with different semantics: after the raise, no more code gets executed).
def egonil(nil_value = nil) yield rescue NoMethodError => e if e.message =~ /NilClass$/ nil_value else raise NoMethodError end end
To use the egonil in daily coding, you can use the zucker gem.
An even more golfed version of the
2826 bytes (from the comments):