The spec on identity expressions was recently changed to:
>For class / interface objects, identity is defined as the object references being identical. Null class objects can be compared with is
. Note that inferface objects need not have the same reference of the class they were cast from. To test whether an interface
shares a class instance with another interface
/ class
value, cast both operands to Object
before comparing with is
.
My sense is that this behavior is surprising and therefore unacceptable. Even the route of simply casting to void*
is unacceptable as it will surprise C++ users who know that dynamic_cast<void*>
, given a pointer to a base-type subobject, returns a void*
to the actual (most-derived) object; that way, two seemingly unrelated class-type objects can be compared for identity without knowing their most-derived type. D doesn’t need that, given that Object
is a known base class for all classes, a cast to Object
achieves the same. If anything, D’s cast(void*)
should do the same as it does in C++, or be invalid. As was pointed out to me, a type paint should be done as per *cast(void**)(&obj)
. DRuntime or Phobos could provide this via a convenience function reinterpretAsVoidPointer
.
If interface identity cannot be done fast enough and correctly, and the language designers don’t want to provide a slow and correct solution as an operator, whatever their rationale may be, they should not provide an incorrect solution, but rather no solution at all, that is, make using the identity operator with one or two interface type values an error. The error message should tell people to use a cast(Object)
; for template code, if a value is a class or interface, note that cast(Object)
is a no-op on class values.
None of this addresses the problem that the cast(Object)
cannot work for extern(C++)
classes, even if C++-RTTI was available, which it hopefully will in the future. A solution would be to do what C++ does: Make cast(void*)
bypass a potential opCast
(akin to how class-type assignment bypasses opAssign
) to return a pointer to the most-derived object the reference refers to. Alternatively, a DRuntime function dynamicCastVoidPointer
could provide this.
Make interfaces easy to use correctly and hard to use incorrectly. – Scott Mayers