Dear all, Currently Groovy breaks the polymorphism contract for the `equals` and `toString` methods for objects implementing List, Set, Map interfaces. For example:
class Mylist extends ArrayList { Mylist(Collection c) { super(c) } @Override boolean equals(Object o) { throw new UnsupportedOperationException () } @Override int hashCode() { throw new UnsupportedOperationException () } @Override String toString() { return 'CUSTOM STRING' } } def l = new Mylist([1,2,3]) assert l.toString() == 'CUSTOM STRING' assert "$l" == '[1, 2, 3]' def q = new Mylist([1,2,3]) assert l.equals(q) assert l == q In the above snippet the `toString` is *not* invoked when interpolated in a GString, also the `equals` method not invoked, not even when it's explicitly referenced. A similar problem for the `equals` method exists when a class implements the `Comparable` interface. For example: class Foo implements Comparable<Foo> { private int x Foo(int x) { this.x=x } @Override int compareTo(Foo o) { throw new IllegalArgumentException('SHOULD INVOKE EQUALS!') } @Override boolean equals(Object o) { return this.x == o.x } } assert new Foo(1).equals(new Foo(1)) // OK assert new Foo(1) == new Foo(1) // throws IllegalArgumentException: SHOULD INVOKE EQUALS! In this case the `==` operator uses `compareTo` instead of the `equals` method. I know there are historical reasons behind each of them, however they represent really nasty inconstancies and cause of a lot of problems. I hope that Groovy 3.0 is planning to solve these problems or at least give a mechanism to implement a proper behaviour. Cheers, Paolo