Reputation: 31477
Last week I wanted to answer a question here on stackoverflow.com, but after running some tests in irb I've found an interesting thing.
class X
def ==(other)
p "X#=="
super
end
end
data = [ 1 ]
data.include?(X.new)
I expect here that Array#include?
will call Fixnum#==
on every item in the array. So the X#==
is never get called and the debug message never gets printed.
But actually in my ruby versions (REE 1.8.7, MRI 1.8.7, 1.9.2 and 1.9.3) it prints out the X#==
debug message.
If I do that on true
or false
or nil
or even Object.new
it never prints out the X#==
message.
But if I redefine the Fixnum#==
like this:
class Fixnum
def ==(other)
p "Fixnum#=="
super
end
end
Which actually calls the original implementation after printing a debug message, it prints out Fixnum#==
and X#==
never gets printed out as I expected originally.
It gets even crazier, when I switch the haystack with the needle:
data = [ X.new ]
data.include?(1)
It prints out X#==
even though it called the #==
method on the needle before.
Could anybody point out what is the reason behind that? Or simply an optimization issue?
Upvotes: 4
Views: 182
Reputation: 79612
So include?
will send :==
to each element of your array.
If your elements are true
, false
, and nil
, the equality test fails readily because only true
is ==
to true
, etc...
For Fixnum
s, it's not that clear, for example 1 == 1.0 # => true
. So Fixnum#==
will be polite in case of an unknown argument and reverse the order of the arguments. This would allow you to define your own "numerical" types.
Now what confused you even more, is that in order to understand what's going on, you redefined Fixnum#==
. Calling super
won't call the original method but Object#==
instead. Try alias_method_chain
(or prepend
if in Ruby 2.0!)
BTW, looking at the actual source, Fixnum
will deal directly with Fixnum
, Bignum
and Float
. For other builtin classes (e.g. Rational
, Complex
, BigDecimal
) as well as user classes, Fixnum#==
will reverse the receiver and the argument. I wouldn't rely on the fact that it does this for Rational
, but all implementations will do this for user classes.
Upvotes: 4