Comparison modes of objects

There are various opinions on how to implement Java standard’s Object.equals(Object) method. According to some, it should be possible to compare different implementations of the same interface or base class. But to follow this policy, each interface or base class’s javadoc must define the algorithms that all implementations shall use for their equals(Object) and hashCode() methods. This approach is common in java.util.Collection and its child interfaces. Transferring this approach to certain GeoAPI interfaces, however, would be a difficult task, and would probably not be followed in many implementations. Moreover, it comes at the expense of being able to take into account supplementary attributes in the child interfaces, unless this possibility has been specified in the parent interface. This constraint arises from the following points of the equals(Object) and hashCode() method contracts:

For example, these three constraints are violated if A (and eventually C) can contain attributes which B ignores. To bypass this problem, an alternative approach is to require that the objects compared by the Object.equals(Object) method be of the same class; in other words, A.getClass() == B.getClass(). This approach is sometimes regarded as contrary to the principles of object oriented programming. In practice, for relatively complex applications, the important accorded to these principles depends on the context in which the objects are compared: if the objects are added to a HashSet or used as keys in a HashMap, we would need a stricter adherence to the equals(Object) and hashCode() contract. But if the developer is comparing the objects his- or herself, for example to check that the relevant information has been changed, then the constraints of symmetry, transitivity or coherence with the hash values may be of little interest. More permissive comparisons may be desirable, sometimes going so far as to tolerate minor discrepancies in numerical values.

In order to allow developers a certain amount of flexibility, many classes in the SIS library implement the org.apache.sis.util.LenientComparable interface, which defines a equals(Object, ComparisonMode) method. The principle modes of comparison are:

The default mode, used in all equals(Object) methods in SIS, is STRICT. This mode is chosen for a safe operation — particularly with HashMap — without the need to rigorously define equals(Object) and hashCode() operations in every interface. With this mode, the order of objects (A.equals(B) or B.equals(A)) is unimportant. It is, however, the only mode that offers this guarantee. In the expression A.equals(B), the BY_CONTRACT mode (and so by extension all other modes that depend on it) only compares the properties known to A, regardless of whether B knows more.