eclipse-archived/ceylon

ensure that 'hash' is unchangeable through contract in 'Object'

Closed this issue · 1 comments

hash should never change for an instance of Object. Having a changeable hash implies that hash sets/maps cannot efficiently and easily satisfy the contract in Iterable.contains.

There is an important consequence implied by this change. That is, for every two non‐variable references obj1 and obj2, the expression obj1 == obj2 should never change its value.

That consequence would be problematic if Ceylon was Java, but since classes with mutable state are considerably rare in Ceylon, I don’t think it’s that this addend to the contract of Object would actually be intrusive.

That is, if a class does have mutable state, one can simply:

  • not rely on it for equality.
  • rewrite the program to not use stateful classes.
  • use the default implementation from Basic/Identifiable.

To illustrate the point, in case it isn’t clear:

import ceylon.collection {HashSet}

class Mutable(shared actual variable Integer hash)
{
    equals(Object that) => that is Mutable && this.hash == that.hash;
}

shared void run()
{
    value mutable = Mutable(0);
    value set = HashSet{mutable};
    
    mutable.hash = 12;
    
    assert(mutable in set); // throws
}

In this case I’m mutating hash directly, however, if hash was a getter depending on a variable attribute, the same effect would be achieved.

I don't think it's possible to enforce this, without doing something incredibly heavy-handed and unreasonable. Closing.