Here are some idioms I can imagine a use for with IdentityObject:
// parameter type
void withLock(IdentityObject monitor, Runnable task)
// type bound
Map<K extends IdentityObject, V> map = ... // gonna lock on keys
// dynamic check
if (x instanceof IdentityObject) {
sync (x) { task(); }
}
else {
sync (GLOBAL_LOCK) { task(); }
}
// reflective check against class
Class<?> c = ...
if (IdentityObject.class.isAssignableFrom(c)) { ... }
The "fake type" approach handles the first two cases well enough. But
it doesn't address the latter two cases; for that we'd need to expose a
Class::isIdentityClass (x.getClass().isIdentityClass()), which seems
workable, though might feel gratuitously different from the first two.
Erasing to Object means that we don't get to do things like overloading:
m(IdentityObject o) { ... }
m(PrimitiveObject o) { ... }
or
m(IdentityObject o) { ... }
m(Object o) { ... }
On 5/5/2021 10:39 AM, Remi Forax wrote:
If it's possible, i would like to discuss about IdentityClass again.
As noted in the last draft, adding IdentityClass automatically at runtime is
not a compatible change if tests that uses Class::getInterfaces() are not
written correctly,
and sadly, a lot of tests are written that way. I'm guilty to having written
those tests too.
I don't believe that the solution is to tweak the reflection because adding
IdentityClass at runtime is already a hack and introducing a hack² (hack square
hack) is usually where we should stop before anyone sanity goes under the bus.
The purpose of IdentityClass is
- to have a classfile for the javadoc describing the behavior of all identity
class
- to be used as type or bound of type parameter.
Apart the result of Class::getInterfaces() being hardcoded, IdentityClass has
to other issues, as javadoc container, given that IdentityClass is inserted by
the VM, it means there is no place in the Java code where someone can click to
see the javadoc in an IDE, we have the same issue with java.lang.Record
currently, the class is added by javac automatically and unlike java.lang.Enum,
there is no method useful on java.lang.Record (equals/hashCode and toString are
defined directly on the record) so very few of my student where able to
understand why a record with a NaN value was equals to itself.
But there is a more serious issue, using IdentityClass is not backward
compatible with Object.
When we have introduced IdentityClass, one scenario was to be able to declare
that the type parameter corresponding to the keys (K) to only support identity
class.
This is not possible using IdentityClass because the erasure of K will be
IdentityClass instead of Object (IdentityClass also appears when the compiler
will to a lub, so the common class of String and URI will be computed as
IdentityClass instead of Object leading to source compatibility issues).
I think at that point, we should go back to our blackboard and see if there is
no other solution.
I see two, one is to do *nothing* and do not add a type saying that only
identity class is a corner case after all,
the other is to piggyback on erasure not unlike Scala does, i.e. IdentityClass
is a fake class that is erased to Object at runtime.
regards,
Rémi