[
https://issues.apache.org/jira/browse/GROOVY-10899?page=com.atlassian.jira.plugin.system.issuetabpanels:comment-tabpanel&focusedCommentId=17656580#comment-17656580
]
Paul King edited comment on GROOVY-10899 at 1/10/23 11:13 AM:
--------------------------------------------------------------
This is a Groovy feature (though sometimes surprises folks). The Groovy {{==}}
operator uses {{compareTo}} for {{Comparable}} instances. This is done to more
closely align the operator with what a non-programmer might expect, e.g.:
{code:java}
assert !1L.equals(1.0d) // traditional Java expectations since they have
different types even though they represent the same mathematical value (in some
sense)
assert 1L == 1.0d // "human" expectations since they represent the same
value
{code}
One workaround (as your example shows) is to explicitly call {{equals}} if you
want a more traditional (from a Java perspective) equals definition.
Some *not recommended* alternatives ({_}if{_} you have control over the
libraries) to change the behavior:
* You could also modify the behavior of {{equals}} to make it the same as
{{{}compareTo{}}}. This might then violate the standard {{equals}} contract.
* You could modify {{compareTo}} to more strictly follow {{{}equals{}}}. This
might also be surprising for Java folks who might expect to be able to compare
different types/units.
* Avoid implementing {{Comparable}} which means Groovy will fallback to just
{{equals}} though this might make the library less useful.
Using the spaceship operator ({{compareTo}}) might illuminate what is happening:
{code}
@Grab('tech.units:indriya:2.1.3')
import tech.units.indriya.quantity.Quantities
import static tech.units.indriya.unit.Units.*
var q1 = Quantities.getQuantity(10, KILOGRAM)
var q2 = Quantities.getQuantity(10_000, GRAM)
println "$q1 ${q1.dump()})"
println "$q2 ${q2.dump()})"
assert q1 !== q2
assert !q1.equals(q2)
assert q1 <=> q2 == 0 // this is equivalent to next line
assert q1 == q2
{code}
was (Author: paulk):
This is a Groovy feature (though sometimes surprises folks). The Groovy {{==}}
operator uses {{compareTo}} for {{Comparable}} instances. This is done to more
closely align the operator with what a non-programmer might expect, e.g.:
{code:java}
assert !1L.equals(1.0d) // traditional Java expectations since they have
different types even though they represent the same mathematical value (in some
sense)
assert 1L == 1.0d // "human" expectations since they represent the same
value
{code}
One workaround (as your example shows) is to explicitly call {{equals}} if you
want a more traditional (from a Java perspective) equals definition.
Some *not recommended* alternatives ({_}if{_} you have control over the
libraries):
* You could also modify the behavior of {{equals}} to make it the same as
{{{}compareTo{}}}. This might then violate the standard {{equals}} contract.
* You could modify {{compareTo}} to more strictly follow {{{}equals{}}}. This
might also be surprising for Java folks who might expect to be able to compare
different types/units.
* Avoid implementing {{Comparable}} which means Groovy will fallback to just
{{equals}} though this might make the library less useful.
Using the spaceship operator ({{compareTo}}) might illuminate what is being
used:
{code}
@Grab('tech.units:indriya:2.1.3')
import tech.units.indriya.quantity.Quantities
import static tech.units.indriya.unit.Units.*
var q1 = Quantities.getQuantity(10, KILOGRAM)
var q2 = Quantities.getQuantity(10_000, GRAM)
println "$q1 ${q1.dump()})"
println "$q2 ${q2.dump()})"
assert q1 !== q2
assert !q1.equals(q2)
assert q1 <=> q2 == 0 // this is equivalent to next line
assert q1 == q2
{code}
> Problem with the equals operator
> --------------------------------
>
> Key: GROOVY-10899
> URL: https://issues.apache.org/jira/browse/GROOVY-10899
> Project: Groovy
> Issue Type: Bug
> Affects Versions: 4.0.7
> Reporter: Damir Murat
> Priority: Major
>
> I'm unsure if this is a general problem or just something with Uom
> ([https://github.com/unitsofmeasurement]) reference implementation.
> However, in the following script, the last assertion fails when it should
> not. I can't tell why, but the equals operator does not end in calling an
> {{equals()}} method in {{tech.units.indriya.AbstractQuantity}} class as it
> should.
>
> {code:java}
> @Grab('javax.measure:unit-api:2.1.3')
> @Grab('tech.units:indriya:2.1.3')
> import javax.measure.Quantity
> import javax.measure.Unit
> import javax.measure.quantity.Mass
> import tech.units.indriya.quantity.Quantities
> import tech.units.indriya.unit.Units
> Quantity<Mass> quantity1 = Quantities.getQuantity(10, Units.KILOGRAM)
> Quantity<Mass> quantity2 = Quantities.getQuantity(10_000, Units.GRAM)
> println "$quantity1 (${Integer.toHexString(quantity1.hashCode())})"
> println "$quantity2 (${Integer.toHexString(quantity2.hashCode())})"
> assert quantity1 !== quantity2
> assert !quantity1.equals(quantity2)
> // Should not fail, but it does
> assert quantity1 != quantity2
> {code}
--
This message was sent by Atlassian Jira
(v8.20.10#820010)