Value-Based Classes - equals/hashCode

Nicolai Parlog nipa at codefx.org
Sun Feb 15 19:53:35 UTC 2015


> Hope this helps.
Yes it does. Ignoring the sand, I'd say I got it.

And I assume this is important because extending equality to the state
of (instead of the reference to) non-value-ish instances threatens the
interchangeability* of values?

* "Instances of a value-based class are freely substitutable when
equal, meaning that interchanging any two instances x and y that are
equal according to equals() in any computation or method invocation
should produce no visible change in behavior."



On 14.02.2015 22:03, Brian Goetz wrote:
>> But yes, also, what's up with that? One interpretation is surely
>> that the StringHolder's string (to stick with that example) can
>> not be accessed as it is "any other object". On the other hand
>> the string is surely part of the holder's state which is
>> expressively allowed to be used for that computation. So what is
>> it?
> 
> Which brings us back to the fundamentally murky part -- what
> comprises the state of an object?
> 
> In languages like Lime (a Java-like language designed for GPU 
> computation), a value type must be "values all the way down".
> (Their primitive data type is "bit"; everything else is defined as
> composites of bit.)  This is a beautiful and clean way to define
> things, but not applicable to the practical problem of adding true
> values to a mutation-happy language like Java; even simple types
> like String require some mental gymnastics to see them as
> value-like (String stores characters in an array, which is mutable,
> but just not mutated after initialization, and even has a
> lazily-initialized, mutable field for the hash code (if that's not
> bad enough, this field is updated using data races!))  But not
> being able to have String as a component of a value would be silly,
> and no one disputes that strings are "value-ish".  But the clean
> definitions don't apply.
> 
> We found ourselves with a related problem when trying to define
> the constraints on behavioral parameters passed to stream methods
> (e.g., the Predicate passed to Stream.filter).  The "obvious"
> restrictions were "side-effect free" or "pure function".  But
> neither of these is the right answer; both are unnecessarily
> restrictive.  (Printing a debug message or updating a history
> buffer are acceptable side effects; looking up data in a mutable
> but not-mutated-during-the-query HashMap is an acceptable
> compromise of purity.)  We settled on a murky definition of
> "non-interfering" and "stateless", knowing full well that our 
> definitions are built on sand, but tried to capture the true spirit
> of the restriction, which is "don't depend on stuff that might
> change during the calculation."
> 
> Said sand includes notions like "what is the state of an object".
> 
> Here's a stab at thinking about this, which I'm sure is wrong, but
> might be a helpful start.  Say a value-ish class C has fields
> c_1..c_n.  Now let's try and define S(C), the variables that
> comprise the "state" of C. S(C) includes: - \forall_i c_i, if c_i
> is a primitive - \forall_i S(c_i), if c_i is a reference to a
> value-ish class - \forall_i c_i, if c_i is a reference to a
> non-value-ish class
> 
> In other words, if a value contains other values, we recursively
> include the dependent value in the state; if a value contains
> references to non-values, we can only include the that reference
> (references are values!), but not any state reachable through that
> reference.  (We wave our hands and magically define certain
> otherwise-problematic classes (like String) to be value-ish.)
> 
> So, in the following class:
> 
> final class Urk { private final MutableStuff mc;
> 
> private Urk(MutableStuff mc) { this.mc = mc; } public Urk
> make(MutableStuff mc) { return new Urk(mc); }
> 
> public boolean equals(Object other) { return (other instanceof
> Urk) && ((Urk) other).mc == mc; }
> 
> // similar for hashCode }
> 
> I would argue this is following the rules; Urk's state includes
> the *reference to* mc, but not the *state of* mc.  If Urk were to
> dive into the state of mc, then it would have crossed the line.
> 
> Hope this helps.
> 

-- 

PGP Key:
    http://keys.gnupg.net/pks/lookup?op=vindex&search=0xCA3BAD2E9CCCD509

Web:
    http://codefx.org
        a blog about software development
    http://do-foss.de
        Free and Open Source Software for the City of Dortmund

Twitter:
    https://twitter.com/nipafx



More information about the valhalla-dev mailing list