I think we should revisit the idea of having the interfaces 
IdentityObject/ValueObject.

They serve two purposes
 1/ documentation: explain the difference between an identity class and a value 
class
 2/ type restriction: can be used as type or bound of type parameter for 
algorithms that only works with identity class

Sadly, our design as evolved but not those interfaces, they do not work well as 
type restriction, because
the type is lost once an interface/j.l.Object is used and the cost of their 
introduction is higher than previously though.
 
1/ documentation

- Those interface split the possible types in two groups
  but the spec split the types in 3, B1/B2/B3, thus they are not aligned 
anymore with the new design.

- they will be noise in the future, for Valhalla, the separation between 
identity object and value object
  may be important but from a POV of someone learning/discovering the language 
it's a corner case
  (like primitives are). This is even more true with the introduction of B2, 
you can use B2 for a long time without
  knowing what a value type is. So having such interfaces front and center is 
too much.


2/ as type

- Being a value class or a primitive class is a runtime behavior not a compile 
time behavior,
  so representing them with special types (a type is a compile time construct) 
will always be an approximation.
  As a consequence, you can have an identity class (resp value class) typed 
with a type which is not a subtype
  of IdentityObject (resp ValueObject).
  
  This discrepancy is hard to grasp for beginners (in fact not only for 
beginners) and make IdentityObject/ValueObject
  useless because if a method takes an IdentityObject as parameter but the type 
is an interface, users will have
  to cast it into an IdentityObject which defeat the purpose of having such 
interface.
  
  (This is the reason why ObjectOutputStream.writeObject() takes an Object as 
parameter and not Serializable)
  

And the cost of introduction is high

- they are not source backward compatible
  class A {}
  class B {}
  var list = List.of(new A(), new B());
  List<Object> list2 = list;

- they are not binary backward compatible
  new Object().getClass() != Object.class

- at least IdentityObject needs to be injected at runtime, which by side effect 
requires patching several
  VM components: reflection/j.l.invoke, JVMTI, etc making the VM spec more 
complex that it should be.


You may not agree with some of my points, nevertheless, the current design is 
not aligned with the B1/B2/B3 world, have a high cost and with little benefit 
so i think it's time to remove those interfaces from the design.

regards,
Rémi

Reply via email to