Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Ruby: target-less 'case', compared to 'if'

Tags:

ruby

(I have asked this question already at Ruby Forum, but it didn't draw any answer, so I'm crossposting it now)

From my understanding, the following pieces of code are equivalent under Ruby 1.9 and higher:

# (1)
case
when x < y
  foo
when a > b
  bar
else
  baz
end

# (2)
if x < y
  foo
elsif a > b
  bar
else
  baz
end

So far I would have always used (2), out of a habit. Could someone think of a particular reason, why either (1) or (2) is "better", or is it just a matter of taste?

CLARIFICATION: Some users have objected, that this question would just be "opinion-based", and hence not suited to this forum. I therefore think that I did not make myself clear enough: I don't want to start a discussion on personal programming style. The reason why I brought up this topic is this:

I was surprised, that Ruby offered two very different syntaxes (target-less case, and if-elsif) for, as it seems to me, the exactly same purpose, in particular since the if-elsif syntax is the one virtually every programmer is familiar. I wouldn't even consider 'target-less if' as "syntactic sugar", because it doesn't allow me to express the programming logic more consisely then 'if-elsif'.

So I wonder in what situation I might want to use the 'target-less case' construct. Does it give a performance advantage? Is it different from if-elsif in some subtle way which I just don't notice?

ADDITIONAL FINDINGS regarding the implementation of target-less case:

Olivier Poulin has pointed out, that a target-less case statement would explicitly use the === operator against the value "true", which would cause a (tiny) perfomance penalty of the 'case' compared to 'if' (and one more reason why I don't see why someone might want to use it).

However, when checking the documentation of the case statement for Ruby 1.9 and Ruby 2.0, I found that they describe it differently, but both at least suggest that === might NOT be used in this case. In the case of Ruby 1.9:

Case statements consist of an optional condition, which is in the position of an argument to case, and zero or more when clauses. The first when clause to match the condition (or to evaluate to Boolean truth, if the condition is null) “wins”

Here it says, that if the condition (i.e. what comes after 'case') is null (i.e. does not exist), the first 'when' clause which evaluates to true is the one being executed. No reference to === here.

In Ruby 2.0, the wording is completely different:

The case expression can be used in two ways. The most common way is to compare an object against multiple patterns. The patterns are matched using the +===+ method [.....]. The other way to use a case expression is like an if-elsif expression: [example of target-less case is given here].

It hence says that === is used in the "first" way (case with target), while the target-less case "is like" if-elsif. No mentioning of === here.

like image 720
user1934428 Avatar asked Jun 30 '15 15:06

user1934428


People also ask

Can you use || IN CASE statement Ruby?

You can't use “||” in case names. But you can use multiple case names without using a break between them. The program will then jump to the respective case and then it will look for code to execute until it finds a “break”.

Does Ruby have switch case?

Ruby uses the case expression instead. Ruby compares the object in the when clause with the object in the case clause using the === operator. For example, 1.. 5 === x , and not x === 1..

What is case in Ruby?

In Ruby, we use 'case' instead of 'switch' and 'when' instead of 'case'. The case statement matches one statement with multiple conditions just like a switch statement in other languages. Syntax: case expression. [when expression [, expression ...]


1 Answers

Midwire ran a few benchmarks and concluded that if/elsif is faster than case because case “implicitly compares using the more expensive === operator”.

Here is where I got this quote. It compares if/elsif statements to case.

It is very thorough and explores the differences in the instruction sequence, definitely will give you an idea on which is better.

The main thing i pulled from the post though, is that both if/else if and case have no huge differences, both can usually be used interchangeably.

Some major differences can present themselves depending on how many cases you have.

n = 1 (last clause matches)
if:           7.4821e-07
threequal_if: 1.6830500000000001e-06
case:         3.9176999999999997e-07

n = 15 (first clause matches)
if:           3.7357000000000003e-07
threequal_if: 5.0263e-07
case:         4.3348e-07

As you can see, if the last clause is matched,if/elsif runs much slower than case, while if the first clause is matched, it's the other way around.

This difference comes from the fact that if/elsif uses branchunless, while case uses branchif in their instruction sequences.


Here is a test I did on my own with a target-less case vs if/elsif statements (using "=="). The first time is case, while the second time is if/elsif.

First test, 5 when statements, 5 if/elsif, the first clause is true for both.

Time elapsed 0.052023 milliseconds                                                                                                                                                                                                                                                                                                                                                                                                       
Time elapsed 0.031467999999999996 milliseconds   

Second test, 5 when statements, 5 if/elsif, the last(5th) clause is true for both.

Time elapsed 0.001224 milliseconds                                                                                                                                                                                                                                                                                                                                                                                                 
Time elapsed 0.028578 milliseconds  

As you can see, just as we saw before, when the first clause is true, if/elsif perform better than case, while case has a massive performance advantage when the last clause is true.

CONCLUSION

Running more tests has shown that it probably comes down to probability. If you think the answer is going to come earlier in your list of clauses, use if/elsif, otherwise case seems to be faster.

The main thing that this has shown is that both case and if/elsif are equally efficient and that using one over the other comes down to probability and taste.

like image 89
Olivier Poulin Avatar answered Nov 15 '22 16:11

Olivier Poulin