You are viewing a plain text version of this content. The canonical link for it is here.
Posted to dev@groovy.apache.org by Paolo Di Tommaso <pa...@gmail.com> on 2018/09/16 16:49:19 UTC

Groovy 3.0 breaking changes

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