According to the groovy docs, the == is just a 'clever' equals() as it also takes care of avoiding NullPointerException. So, the == and equals() should return the same value if the objects are not null. However, I'm getting unexpected results on executing the following script:
println "${'test'}" == 'test'
println "${'test'}".equals('test')
The output that I'm getting is
true
false
An example of this can be found here.
Is this a known bug related to GStringImpl or something that I'm missing?
Nice question, the surprising thing about the code above is that
println "${'test'}".equals('test')
returns false
. The other line of code returns the expected result, so let's forget about that.
Summary
"${'test'}".equals('test')
The object that equals
is called on is of type GStringImpl
whereas 'test'
is of type String
, so they are not considered equal.
But Why?
Obviously the GStringImpl
implementation of equals
could have been written such that when it is passed a String
that contain the same characters as this
, it returns true. Prima facie, this seems like a reasonable thing to do.
I'm guessing that the reason it wasn't written this way is because it would violate the equals
contract, which states that:
It is symmetric: for any non-null reference values x and y, x.equals(y) should return true if and only if y.equals(x) returns true.
The implementation of String.equals(Object other)
will always return false when passed a GSStringImpl
, so if GStringImpl.equals(Object other)
returns true when passed any String
, it would be in violation of the symmetric requirement.
In groovy a == b
checks first for a compareTo
method and uses a.compareTo(b) == 0
if a compareTo
method exists. Otherwise it will use equals
.
Since Strings and GStrings implement Comparable
there is a compareTo
method available.
The following prints true, as expected:
println "${'test'}".compareTo('test') == 0
The behaviour of ==
is documented here.
In Java ==
means equality of primitive types or identity for objects. In Groovy ==
translates to a.compareTo(b)==0
, if they are Comparable
, and a.equals(b)
otherwise. To check for identity, there is is
. E.g. a.is(b)
.
For other operators see this table: http://docs.groovy-lang.org/docs/latest/html/documentation/#Operator-Overloading
Linked table provided inline for posterity, in case the above link breaks again.
| Operator | Method |
|----------|-------------------------|
| + | a.plus(b) |
| a[b] | a.getAt(b) |
| - | a.minus(b) |
| a[b] = c | a.putAt(b, c) |
| * | a.multiply(b) |
| a in b | b.isCase(a) |
| / | a.div(b) |
| << | a.leftShift(b) |
| % | a.mod(b) |
| >> | a.rightShift(b) |
| ** | a.power(b) |
| >>> | a.rightShiftUnsigned(b) |
| | | a.or(b) |
| ++ | a.next() |
| & | a.and(b) |
| -- | a.previous() |
| ^ | a.xor(b) |
| +a | a.positive() |
| as | a.asType(b) |
| -a | a.negative() |
| a() | a.call() |
| ~a | a.bitwiseNegate() |