On Tuesday 06 July 2010, Pieter H. wrote:
|==> 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