Why does he call the "wrong" equal method?

Last week, I wanted to answer the question here /qaru.site / ... , but after running some tests in irb, I found an interesting thing.

class X def ==(other) p "X#==" super end end data = [ 1 ] data.include?(X.new) 

I expect Array#include? will call Fixnum#== for each element of the array. Thus, X#== never called, and the debug message is never printed.

But in fact, in my ruby ​​versions (REE 1.8.7, MRI 1.8.7, 1.9.2, and 1.9.3) it displays the debug message X#== .

If I do this on true or false or nil or even Object.new , it never prints the X#== message.

But if I redefine Fixnum#== as follows:

 class Fixnum def ==(other) p "Fixnum#==" super end end 

What actually causes the original implementation after printing the debug message, it prints Fixnum#== and X#== will never be printed, as I expected initially.

Update

This gets even crazier when I switch the haystack with a needle:

 data = [ X.new ] data.include?(1) 

It outputs X#== , although he used to call the #== method on the needle.

Can anyone indicate what is the reason for this? Or just an optimization problem?

+4
source share
1 answer

So include? will send :== each element of your array.

If your elements are true , false and nil , the equality test fails because only true from == to true , etc.

For Fixnum s, this is not so clear, for example 1 == 1.0 # => true . Thus, Fixnum#== will be polite in case of an unknown argument and will change the order of the arguments. This will allow you to define your own "numeric" types.

Now, what has even more embarrassed you, you have overridden Fixnum#== to understand what is happening. A call to super will not call the original method except Object#== . Try alias_method_chain (or prepend if in Ruby 2.0!)

By the way, looking at the actual source, Fixnum will deal directly with Fixnum , Bignum and Float . For other built-in classes (for example, Rational , Complex , BigDecimal ), as well as user classes, Fixnum#== will override the receiver and argument. I would not rely on the fact that he does this for Rational , but all implementations will do this for custom classes.

+4
source

All Articles