Groovy different results on using equals() and == on a GStringImpl

Anuj Arora picture Anuj Arora · Mar 13, 2012 · Viewed 49.2k times · Source

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?

Answer

Dónal picture Dónal · Mar 13, 2012

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.