Sunday, July 22, 2007

Ruby: Multiple ifs (unless)

I recently ran into some code similar to the snippet below.

item.currency if item.currency != :usd unless item.nil?

Based on reading the code I assumed it worked as expected; however, having never actually tried it myself I decided to hit irb for a moment with the following code.

p 3 unless p 2 unless p 1

Sure, I'm not using if, but if and unless have the same precedence, so I thought the example was good enough.

p 3 unless p 2 unless p 1
# >> 1
# >> 2
# >> 3

The output shows the execution order: The rightmost if (or unless) is evaluated first and then it moves to the next conditional immediately to it's left.

Of course, the statement could be rewritten simply using ||.

item.currency unless item.nil? || item.currency == :usd

Due to short circuit evaluation neither statement executes item.currency != :usd if item.nil?.

Labels: , ,




Comments:
This works because "if" or "unless" are themselves normal expressions (as opposed to regular expressions ;).

As mentioned in the docs however, "This path leads to the gates of madness."!
 
Jay,

I'm not sure that your example expression:

p 3 unless p 2 unless p 1

really shows what you want to.

The problem is that the p method returns nil, so that none of the unless logical expressions evaluate to true.

Here's a more realistic experiment:
irb(main):001:0> p 2
2
=> nil
irb(main):002:0> def q(a)
irb(main):003:1> p a
irb(main):004:1> a
irb(main):005:1> end
=> nil
irb(main):006:0> q 3 unless q 2 unless q 1
1
=> nil

the q method returns it's argument with the side effect of printing it. Note that the unless statement modifiers are evaluated right to left, so only the last invokation of q happens.

By the way, one of your recent blogs just triggered me to write this.
 
Post a Comment

<< Home

This page is powered by Blogger. Isn't yours?