[concurrency-interest] Should I avoid compareAndSet with value-based classes?

Gil Tene gil at azul.com
Thu Jul 6 17:57:04 EDT 2017

On Jul 6, 2017, at 1:56 PM, Alex Otenko <oleksandr.otenko at gmail.com<mailto:oleksandr.otenko at gmail.com>> wrote:

What’s wrong with “==“ doing a sensible default thing? Like, bitwise compare the “contents”? It’s certainly no slower than calling equals() that perhaps will do more than just bitwise-compare.

Nothing "wrong" with that if we had a good specification on WHEN it means that. And "when both sides of the == are instances of value-based classes" probably doesn't cut it.

To see why, the javac compiler won't let us write:

int i = 0;
Object o = new Object();
boolean b = (o == i);

That's because int is NOT AN OBJECT.

But javac absolutely does let us write:

Object o1 = getSomeObject();
Optional o2 = getSomeOtherObject();
boolean b = (o1 == o2);

What does that == mean? What can it mean without being "surprising"?

And while it's tempting to say that here:

Optional o1 = Optional.of(objA);
Optional o2 = Optional.of(objB);
boolean b = (o1 == o2);

The == means "compare the contents". What should it mean here:

Object o1 = Optional.of(objA);
Object o2 = Optional.of(objB);
boolean b = (o1 == o2);

I suspect that the curse of being the basterd children of Object will follow instances of value based classes around for generations to come… It will be curious to see how value types deal with this same problem in an eventual working syntax.

What’s wrong with identityHashCode producing a code based on identityHashCodes of the “contents”, or the bit contents of the primitive members?

Similarly, identityHashCode already has a meaning for Object, where it will NOT be computed based on contents. Changing that for the basterd children of Object will create all sorts of in-fighting in the family:

Optional o1 = Optional.of(objA);
int ihc1 = System.identityHashCode(o1);
Object o2 = o1;
int ihc2 = System.identityHashCode(o2);
boolean b = (ihc1 == ihc2); // Is this allowed to be False?


On 6 Jul 2017, at 20:23, Gil Tene <gil at azul.com<mailto:gil at azul.com>> wrote:

I think that performant runtime checks can be added. When you haven't stuffed indentity-lacking things into other things that explore identity, things will be just as fast. When you do, they will blow up, and speed won't matter.

The larger problem of "surprising behavior" when passing a non-identity-capable thing (basterd child of Object) to some thing that expects Object and does object things with it at some future point in time (like maybe using identity for something) is likely to come at us hard when "codes like a class, works like an int" value types are introduced. IMO, it is "hard" (as in impractical) to compile-time check this stuff away completely. You can cover some (many?) cases, but runtime issues will always remain. The situation where people are appalled at what can happen with instances of value-based classes that they may pass to innocent Object-expecting things is just a glimpse of the future. IMO an exception is the least bad thing you can do to them. Much better than letting their code run.

— Gil.

On Jul 6, 2017, at 11:52 AM, Brian S O'Neill <bronee at gmail.com<mailto:bronee at gmail.com>> wrote:

Although it would be nice to have value-based classes truly supported, because the java.time classes are defined as ordinary classes, they can never change into becoming true value-based classes without breaking compatibility. You can't just change the definition of instance equality without completely breaking the language completely. Improper use of a weak value-based class should at the very least trigger a compiler warning, but a full runtime check is too extreme.

Consider how these checks are implemented by the compiler. Adding a runtime check would be equivalent to making every == check, cas, etc behave like a virtual method call. I wouldn't be terribly happy to see a performance regression introduced in something so fundamental and used everywhere.

Also consider problems resulting an exception thrown from the == operator. This isn't supposed to happen. Any piece of code which is designed to be fault tolerant (via exception handling) is now broken, because it assumed (correctly) that fundamental language design elements don't change.

On 2017-07-06 11:15 AM, Gil Tene wrote:
David, the below is a (potentially good) argument for not allowing the creation of subclasses of Object that do not have well defined support identity, identity comparison, identity hashing, or synchronization, since Object supports all those, things that hold Object instances may very well make use of them.
But that horse has long fled the barn. We can argue that value-based classes should not have been specified in Java 8. Or that the future value types should not be derived from Object. But the first case is already in the Java spec, and the second is likely coming (and is sneakily able to use the first as a precedent).
For the "how should we specify things?" discussion, I'm actually squarely on the side of "things with no identity should never have been derived from Object" of this argument. E.g. I would advise other language specifications to avoid making the same mistake, either by not giving the base Object class identity to begin with, or by creating a separate orthogonal type hierarchy for value types and "value based" classes. However, I don't see a way to "fix" the mistake already made, and we have to deal with the language and the machine as spec'ed, not as we wish it were. And so does anyone writing code in the language.
In the context of that reality, we are discussing what correct uses of those new "basterd children of Object" are. And since the basterds clearly have no identity, using any logic that relies on identity behavior in any way is wrong.
Sent from my iPad
On Jul 6, 2017, at 10:53 AM, Gil Tene <gil at azul.com<mailto:gil at azul.com> <mailto:gil at azul.com>> wrote:
Hence my suggestion that identity-based operations on instances of value-based classes should throw exceptions... Right now they silently do unpredictable things, and should be avoided in any case (but harder to know/find when you accidentally use them).

Sent from my iPad

On Jul 6, 2017, at 10:46 AM, Alex Otenko <oleksandr.otenko at gmail.com<mailto:oleksandr.otenko at gmail.com> <mailto:oleksandr.otenko at gmail.com>> wrote:

Are they subclasses of Object or not? If they are not, no questions. If they are, someone still needs to explain how exactly the “identity based operations” can be avoided safely.

List<j.u.Optional> is just a List underneath, and searching for an item may use “identity based operations”, whether you want it or not - depending on what implementation of List you happen to use.


Concurrency-interest mailing list
Concurrency-interest at cs.oswego.edu<mailto:Concurrency-interest at cs.oswego.edu>

Concurrency-interest mailing list
Concurrency-interest at cs.oswego.edu<mailto:Concurrency-interest at cs.oswego.edu>

-------------- next part --------------
An HTML attachment was scrubbed...
URL: <http://cs.oswego.edu/pipermail/concurrency-interest/attachments/20170706/80f47ca6/attachment-0001.html>

More information about the Concurrency-interest mailing list