Introduction
In this article, we’ve covered everything you need to know about point equality in ruby. Ruby is a high-level, general-purpose, interpreted programming language that supports a variety of paradigms.
Point Equality in Ruby
Even if two separate Point instances have identical X and Y coordinates, they will never be equal to each other, that’s where point equality in ruby comes in. We need to offer an implementation of the == operator to fix this.
An == method for Point Equality in Ruby is as follows:
def ==(p) # Is self == p?
if p.is_a? Point # to check if p is a Point object
@x==p.x && @y==p.y # compare parameters
elsif # In case p is not a Point object
false # then, self != p.
end
end
Recall that Ruby objects also define an eql? method for determining equality.
The eql? method, like the == operator, checks object identity by default rather than object content equality. We can make eql? behave frequently like the == operator by giving it an alias:
class Point
alias eql? ==
end
However, there are two situations in which we would wish eql? to differ from ==.
A stricter comparison than == is performed by some classes' definitions of eql? For instance, == permits type conversion in Numeric and its subclasses but eql? does not. We might use this example if we think that users of our Point class would need to be able to compare instances in two different ways. Points are essentially two integers, thus it seems logical to follow Numeric's lead in this instance. Similar to the == function, our eql? method compares point coordinates using eql? rather than ==:
def eql?(o)
if o.instance_of? Point
@x.eql?(o.x) && @y.eql?(o.y)
elsif
false
end
end
Note that all classes that implement collections (sets, lists, or trees) of arbitrary objects should use this strategy. Both the == operator and the eql? method should compare the collection's members using their respective == operators and eql? Methods.
If you wish instances of your class to behave differently when used as a hash key, you should implement an eql? method that differs from the == operator. To compare hash keys, the Hash class makes use of eql? (but not values). Hashes will compare instances of your class according to object identity if you leave eql? undefined. In other words, if you assign a value to a key p, you can only retrieve that value from the same object p. Even if p == q, an object q won't function. Mutable objects are poor hash key candidates, but leaving eql? undefined neatly avoids the issue.
You must never use this method alone because eql? is used for hashes. To generate a hashcode for your object, you must specify a hash method if you define an eql? method. When two objects are considered equal by eql?, their hash methods must have the same result.
It can be challenging to implement the best hashing algorithms. Fortunately, there is a straightforward method to get exactly acceptable hashcodes for almost any class: just add the hashcodes of all the objects your class references. (To be more specific, combine the hashcodes of all the items your eql method compared.) Combining the hashcodes correctly is the trick. The hashing technique listed below is not recommended:
def hash
@x.hash + @y.hash
end
Because this technique gives the same hashcode for the point (1, 0) as it does for the point, it contains a flaw (0,1). Although it is permitted, using points as hash keys results in below performance. Instead, let's change things up a little:
def hash
code = 17
code = 37*code + @x.hash
code = 37*code + @y.hash
# For each significant instance variable, add lines like this.
code # return the outcome's code.
end
This all-purpose hashcode formula ought to work with the majority of Ruby classes. It and its constants 17 and 37 were taken from Joshua Bloch's book Effective Java.