Hello, I need a sponsor for following JDK change.
Summary ------- Provide means for type safe comparison for equality by introducing type-parameterized interface `java.lang.Equable<T>` with method `boolean equ(T)`. (The actual names of the interface and the method is subject to discussion.) Goals ----- The primary goal is to avoid programmer mistakes when values of different and incomparable types are compared using `equals` method, which always returns `false` in such cases according to its contract. Non-Goals --------- Custom hashers and equators for Collection Framework are out of the scope of this proposal. Motivation ---------- This is quite common approach to use `equals` method to compare value for equality. However, it may happen that the values have different incomparable types and, therefore, the result of such a comparison is doomed to `false`. For example, instances of `java.lang.Integer` and `java.lang.Long` will never be equal even though they represent the same numerical value. I.e. this code Long l = 42L; Integer i = 42; if (l.equals(i)) { // always false ... } else { ... } is very likely a mistake because the else-branch will never be taken. The same applies to attempts to compare among themselves instances of `java.lang.Short`, `java.lang.String`, `java.util.Date`, `java.util.List`, `java.util.Set`, `java.util.Map` etc. The reason why such erroneous comparisons remain unnoticed is the fact that the `equals` method accepts any value. One way to make mistakes with such comparisons more visible it to use `compareTo` method. Long l = 42L; Integer i = 42; if (l.compareTo(i) == 0) { // compilation error ... } else { ... } However this approach has some drawbacks: * It's counter-intuitive and unnecessarily verbose. It's not clear at glance why `compareTo` is used instead of `equals`. * It can be inefficient because there are cases when an attempt to figure out whether given value is less or greater that the other value requires more effort than an attempt to figure out whether the values are just not equal. For example, when we compare strings and have noticed that the strings have different length we can stop here and do not scan them in order to figure out, which one is greater than the other. Another example is the class that represents rational number as a reduced fraction. To make sure that the rational numbers are equal, we can just compare their numerators and denominators. But in order to find out which one is greater than the other we can't avoid arithmetic operations (multiplications). * It's not applicable to the classes that do not implement `java.lang.Comparable<T>`. For example, collections, complex numbers, points in 2D or 3D space etc. Therefore it's proposed to introduce interface `Equable` in order to explicitly mark comparable classes. public interface Equable<T> { boolean equ(T o); } Let `Comparable` extend it and provide default method for `equ`. public interface Comparable<> extends Equable<T> { int compareTo(T o); default boolean equ(T o) { return compareTo(o) == 0; } } Provide efficient implementation of `equ` method for some JDK classes, at least those that are in `java.lang` package. Also it would be desiable to let `java.util.List`, `java.util.Set`, `java.util.Map` and `java.util.Map.Entry` to extend `Equable` interface as well (but without extending `Comparable`). === I am sending a set of patches. I split the whole change into several logical parts. * equable-0.patch contain `java.lang.Equable`, `java.lang.Comparable`, `java.util.Objects.equ` * equable-1.patch contain `j.l.Boolean`, `j.l.Byte`, `j.l.Character`, `j.l.Double`, `j.l.Enum`, `j.l.Float`, `j.l.Integer`, `j.l.Long`, `j.l.Short` and `j.l.String` * equable-2.patch contain `j.u.Optional`, `j.u.OptionalDouble`, `j.u.OptionalInt`, `j.u.OptionalLong` * equable-3.patch contain `j.u.List`, `j.u.AbstractList`, `j.u.Set`, `j.u.AbstractSet`, `j.u.Map`, `j.u.AbstractMap` * equable-4.patch is a tricky one. It contains `com.sun.tools.jdi.EventSetImpl`. Previously this class extended `java.lang.ArrayList` and implemented `java.lang.Set` through `EventSet`. Therefore it appeared that it implemented both `java.util.List` and `java.util.Set` at the same time. This is not right, because these interfaces have different contracts regarding equality. So I had to change it by extending `java.lang.AbstractSet`. Thank you, Dmytro