if_not_nil?
A fellow blogger emailed to ask what I thought of
Object#if_not_nil. and how it compares to
Object#andand, something I created for a similar purpose.
Well, technically they do exactly the same thing if you supply a block or fake it using something like Symbol#to_proc:
foo.if_not_nil { |f| f.bizzat } == foo.andand { |f| f.bizzat }
foo.if_not_nil(&:bizzat) == foo.andand(&:bizzat)
Object#andand does some proxy magic to let you invoke methods directly. At the moment,
1 Object#if_not_nil does not. You can fake it with Symbol#to_proc if you don’t have parameters or a block, but if you want parameters or a block, you have to supply an explicit block to Object#if_not_nil:
foo.andand.bizzat == foo.if_not_nil(&:bizzat)
foo.andand.bizzat(:smyg, :tzzz) ==
foo.if_not_nil { |f| f.bizzat(:smyg, :tzzz) }
foo.andand.inject([]) { |a,n| a.me.push(n) } ==
foo.if_not_nil { |f|
f.inject([]) { |a,n| a.me.push(n) }
}
Do these extra explicit blocks matter? They matter to
me, the whole point of the exercise was to make the code to do these things very easy to understand at a glance. Object#andand is an attempt to “decorate” a method call, not an attempt to call a particular block if and only if the parameter to the block is not null.
Now, I have read at least one view that Object#if_then_nil “expresses what the code is doing.” I think that is a Good Thing, code that says what it does. However, there is another view about code, a view that abstractions matter. Object#andand is not an attempt to provide an abbreviated way to write:
foo.bar if !foo.nil?
Instead, Object#andand attempts to create an entirely new kind of method call:
foo&&.bar
behind the scenes it may do exactly the same thing, or it may have a completely different implementation based on proxies. Object#andand presents a certain abstraction and does not ask you to think of proxies or blocks or if statements, just of a guarded method call.
Therefore, honestly, if you are already “thinking in if statements,” the existing Object#if_not_nil ought to be very natural: if statements delimit blocks of code. When what you are trying to emphasize with your code is the conditional and the block to be executed, the Object#if_not_nil is for you.
On the other hand, if you are thinking of a method invocation but want to guard it just in case the receiver is nil, then you may find yourself looking at Object#if_not_nil and asking yourself why you need a block and a parameter just to send something a method. When what you are trying to emphasize about the code is the method invocation, I suggest Object#andand is the more readable approach.
- Of course, Object#if_not_nil could gain this functionality in a future release. I think that would be very nice, but of course the author may not care for the style of coding or for the potential hassles of a method that returns a proxy object. Object#andand is released under the MIT license specifically to allow people to reuse all or part of it as they see appropriate.