|Hi guys
|
|Thanks for the prompt and helpful responses. Your proposals work, but I
|am still unhappy about spending an hour tracking this bug.
|
|So CASE uses '===' and not '==', am I correct? So why does
|
|a = 1
|a === Fixnum
|
|==> false
Because that uses
1 === Fixnum
that is it calls the === method of 1, rather than the === method of Fixnum.
Fixnum#=== works like Fixnum#== (note here we're speaking of the === instance
method of Fixnum, as shown by the use of the # symbol, rather than of the ===
class method I spoke of in my other message and which is indicated using the .
symbol), so 1 === Fixnum returns false because Fixnum is not a number and so
can't be equal to 1.
|Furthermore, In my original example, one would expect a.class === Fixnum
|to return true in any case, as '===' is supposed to be more forgiving
|than '==', but it doesn't.
You shouldn't think of === as being more forgiving than ==. According to the
documentation of Object#===:
Object#===
Case Equality--For class Object, effectively the same as calling #==, but
typically overridden by descendents to provide meaningful semantics in case
statements.
This means that === is not a more forgiving version of ==. It's an operator
which is written so that it makes things easier in a case statement. For
example, take the class Regexp. Suppose I have a string str and I want to test
which regexp matches it. I can write:
case str
when /a/
...
when /b/
...
when /c/
...
else
...
end
This can be done because Regexp#=== returns true or false depending on the
value returned by its match? method.
The same happens for Ranges. If n is an integer, I can write:
case n
when 1..3
...
when 5..6
...
else
...
end
Again, this works as I expect because Range#=== uses the include? method to
determine whether to return true or false.
For certain classes, instead, the more sensible behaviour for this method is
to work like ==. This is what happens with Integer, String and Array, for
example.
Now, regarding your case. When you put a class in a When clause, what do you
usally want to do? Check whether the object being tested is an instance of
that class. So Class#=== returns true if the object is an instance of the
class and false if it isn't. And since Fixnum is not an instance of Fixnum,
you get false.
|This is all a bit counter intuitive to me and !(least surprising).
Once learnt that case statements use the === operator (and I think most of the
ruby books mention it when they speak of case), I had no issue with this.
Indeed, I think it's a simple way to be able to use the case statement in a
meaningful way also with custom classes (otherwise, you'd be limited to use it
only with built-in classes, as in C, where you can't even use it with
strings).
I hope what I said clarified things at least a bit.
Stefano