Reputation: 3908
Why does the if
statement work in the example below while the switch statement does not.
working:
if ''.class == String
puts "yep, that's a string"
end
not working:
case ''.class
when String
puts "yep, that's a string, but this case is never triggered"
end
In the trivial example above, the switch statement is overkill, but there are obviously situations where a switch statement would be DRYer than chained elsif
s
Upvotes: 3
Views: 380
Reputation: 12251
The quick and simple answer is that case uses ===
(3 equals) and not two.
$ irb
if ''.class == String
puts "yep, that's a string"
end
yep, that's a string
=> nil
if ''.class === String
puts "yep, that's a string"
end
=> nil
Upvotes: 5
Reputation: 6337
As others have said, case
equality in Ruby works a bit differently than you might expect, so you can just do
case foo
when String # that is, when String === foo, more or less when foo.class == String
do something
end
But generally, you shouldn't. If you're explicitly testing class names, then (usually) your OO design is flawed -- in most cases, you should try to use polymorphism instead. In other words, instead of
if x.class == String
x.process_string
else
x.process_non_string
end
you should simply have x.process
, and then define process
differently for String
and other classes. Cleaner, less code, doesn't force the caller to know the class of the called object.
Upvotes: 3
Reputation: 8116
This is because the case statement doesn't use the == operator, it uses the === operator (sometimes called the case equality operator). What this does varies depending on what's on the left side of the operator. So, if you were to transform case statement like this:
case "Some string"
when String
puts "It's a string!"
else
puts "It's not a string!"
end
Into an if statement, it would become this:
if String === "Some string"
puts "It's a string!"
else
puts "It's not a string!"
end
Note that Ruby does this backwards from how you'd expect, it does String === "Some string"
. This is because what you really want to do is call Class#===
here, and not String#===
. What the === operator does for any object is really up to the class. In the case of Class#===
, it's roughly equivalent to calling "Some string".is_a?(String)
. But if you were to do "a" === "b"
, the String#===
method is roughly equivalent to String#==
.
It can get confusing, but the operator's usage is largely idiomatic. In other words, the "class object in a when statement" idiom means to test if the case object is of that class. I've written an article on this that explains it a bit more, you can read it here.
Upvotes: 5
Reputation: 2746
Actually, ruby's "case" makes the comparaison with ===
So your example is equivalent to :
if ''.class === String
puts "yep, that's a string"
end
Upvotes: 11