Ruby Ternary operator re-written with Boolean operators

Just noticed something interesting (well not that interesting). Ternary operators in Ruby can be re-written using Boolean operators e.g.

method = object.respond_to?(:foo) ? :foo : :bar

would become…

method = object.respond_to?(:foo) && :foo || :bar

Simply replace ? with && and : with ||

I don’t know if there is any performance gain here, anyone care to investigate?

7 comments ↓

#1 Rik Hemsley on 08.23.07 at 2:40 pm

“I don’t know if there is any performance gain here, anyone care to investigate?”

Not really. I’m not in the habit of obfuscating my code to take advantage of minor (it can’t be anything but) performance gains. Also, who’s to say the interpreter won’t change to make the alternate method faster in the future?

#2 Jamie Hill on 08.23.07 at 4:14 pm

Rik: Ohhh… touchy! It was only a simple observation.

I wasn’t advocating a complete paradigm shift. Just wondered if anyone had come across it before and had noticed any performance gains.

#3 Jonas on 08.23.07 at 7:09 pm

That’s a quite normal pattern in Python. There is one caveat to be aware of though, if you do “foo = a and b or c” you have to make sure b can’t evaluate to false (because then the expression will return c).

#4 Jamie Hill on 08.23.07 at 7:54 pm

Jonas: Very good point, I hadn’t thought of that.

#5 raggi on 08.23.07 at 10:57 pm

You’re potentially performing two boolean operations too.

During benchmarking of a simple string building algorithm, I ended up looking at some of the more minor performance areas, like the boolean operators and functions.

Originally I ‘discovered’ that if/else was faster than the ternary operator; however, further testing revealed this had more to do with specific testing code than anything else.

if true
true
else
false
end

is slower than

true ? true : false

However, their logic are the same.

Further testing (with the help of zenspider, probably more to his annoyance than anything else), I realised that:

if true then true else false end

is effectively the same speed as the ternary operator.

Interesting? Maybe.

Using ‘return’ instead of implicit return values I also found to be slower.

On that note, you can also do this (which clearly isn’t faster, it’s just interesting) (from #ruby-lang):

# 02:38 flgr: interestingly, Array#empty? can be implemented as ary.inject(true) { false }
# 02:39 flgr: what this means is that you can replace ary.empty?() ? a : b with ary.inject(a){ b } all the time
# 02:50 flgr: raggi: you can probably make it faster by using { break b } :)

N.B. that break, like return, is slightly slower than not doing so, using the tests that I built some time ago, which may need to be re-done.

Analysis of speed at this level is extremely difficult from within the language, and is massively sensitive to environmental influence. It’s almost easier to look at the source and rely on that.

#6 raggi on 08.24.07 at 1:56 am

sidenote: the first example of the if/else block should have newlines, the latter should not.

Apologies for the complete lack of formatting.

#7 Jamie Hill on 08.24.07 at 11:33 am

raggi: Thanks, interesting stuff. I suppose it all comes down to boolean comparisons at the end of the day and the more operations needed the slower things will be (same with SQL queries).

Also speed depends on whether the value before the operator evaluates to true i.e. true || false would be faster than false || true as in the first example, the second value does not need checking but it does in the latter.

The inject for empty? is interesting, inject always makes my brain ache even though I’ve been using it for years.

Leave a Comment