Comparing Object Equivalence in Ruby

I am doing a Ruby tutorial here: http://rubymonk.com/learning/books/4-ruby-primer-ascent/chapters/45-more-classes/lessons/105-equality_of_objects

Saying when I overload the == operator, should I also overload the eql? method eql? and hash methods because they are "faster."

However, if I overload all three essentially with the same method, how is one faster than the other?

+6
source share
2 answers

In most cases == and eql? have the same result. In some cases, eql? is more strict than == :

 42.0 == 42 # => true 42.0.eql?(42) # => false 

Because of this, if you define == , you probably want to define eql? as well eql? (or vice versa).

eql? assumption been made that the Hash class will use eql? to distinguish between different keys, not == . It could be == , mind you, but eql? was cleaner.

To avoid costly eql? calls eql? all the time, the value of the hash function is calculated with the requirement that two eql? must have the same hash value. This hash value is stored, which makes searching in the future very simple: if the hash code does not match, then the values ​​are not eql? ...

For this reason, should you define Hash reasonable way if you define eql? .

Note that calculating a hash value is almost always more expensive than comparing with == or eql? . However, if the hash is calculated, checking if the hashes match is very fast.

Because hashes usually involve a lot of comparisons, a relatively expensive hash calculation is done once for each key, and then once for each search. Imagine a hash with 10 inputs. It will take 10 Hash calls to create it before the first search is completed. The first search will be relatively quick: a single Hash call, followed by a very efficient hash code comparison (this is actually faster than this, as they are “indexed”). If there is a match, do you still need to call eql? to ensure real fit. Really, two objects which are not eql? can have the same hash. The only guarantee is that there are two eql? must have the same hash, but two different objects can have the same value.

If you want to do the same with Array , you may need 10 eql? calls eql? for every search.

Why is it worth it, I don’t think that the ruby ​​primer you are referring to is as clear as possible. He neglects the fact that calculating Hash can be expensive, so this is only done when it makes sense, i.e. When it is a good assumption that each element will be compared many times. Moreover, it is a shame that an example of custom eql? which it gives uses == to compare instance variables. Ideally would he use eql? for consistency, just like arrays == if its elements == , and arrays eql? if its elements are eql? . Finally, is it really worth mentioning Struct , which defines decent == , Hash and eql? for you.

+13
source

For example, Array#hash says -

Two arrays with the same contents will have the same hash code (and will be compared using eql?).

and Array#== says:

Equality - two arrays are equal if they contain the same number of elements, and if each element is equal (according to object # ==) the corresponding element in other_ary.

and Array#eql? He speaks

Returns true if self and other objects are the same object or are arrays with the same content.

So, according to the documentation, it is clear that eql? faster because it uses hash value with eql? . While #== does two things -

  • array length and
  • checking each element of equality.
+3
source

Source: https://habr.com/ru/post/943574/


All Articles