I’ve not found this stated clearly enough elsewhere so I’m doing so myself.
Ruby’s case statement calls the === method on the argument to each of the when statements
So, this example:
case my_number
when 6883
:prime
end
Will execute 6883 === my_number
This is all fine and dandy, because the === method on a Fixnum instance does what you’d expect in this scenario.
However, the === method on the Fixnum class does something different. It’s an alias of is_a?
That is cute, because it allows you to do this:
case my_number
when Fixnum
"Easy to memorize"
when Bignum
"Hard to memorize"
end
But it won’t work as you might expect in this scenario:
my_type = Fixnum
case my_type
when Fixnum
"Fixed number"
end
This won’t work because Fixnum === Fixnum returns false because the Fixnum class is not an instance of Fixnum.
My workaround for this is to convert it to a string first. Not sure if that’s the best solution, but it works for me(tm).
my_type = Fixnum
case my_type.to_s
when "Fixnum"
"Fixed number"
end
John Leach is a human being living in Leeds, UK.
August 30th, 2009 at 20:14
Any idea of the original rationale for the crazed implementation of Fixnum.=== ?
>> Fixnum === Fixnum
=> false
doesn’t seem like a good move to me!
August 30th, 2009 at 22:45
Rahim, it’s possible that it’s optimized for case statement usage, which is pretty neat to be honest. Was just unexpected to me until I understood what was going on.
In fact, the docs suggest that:
http://www.ruby-doc.org/core/classes/Object.html#M000345
August 30th, 2009 at 23:38
=)
I read the docs and still couldn’t see when that choice would help for case statements (perhaps because I was biased by your example…)
Another, at first glance odd, result this leads to is eg:
>> Fixnum === 2
=> true
>> 2 === Fixnum
=> false
August 30th, 2009 at 23:52
I think misread your initial post, I thought you were saying your second example didn’t work as expected (which looking at it again looks like a pretty common pattern which made it all the more surprising).
Googling gives a few people who’ve discussed the same behavior (http://www.justskins.com/forums/doing-a-case-on-class-23663.html, http://blog.jayfields.com/2007/03/ruby-operator.html), both of whom quote the ri docs for Module#=== which explains my observations :
——————————————- Module#===
mod === obj => true or false
—————————————————–
Case Equality—Returns +true+ if _anObject_ is an instance of
_mod_ or one of _mod_’s descendents. Of limited use for modules,
but can be used in +case+ statements to classify objects by class.
December 29th, 2009 at 17:09
Do this =>
my_type = Fixnum
case my_type
when Fixnum:
“Fixed number”
end