D is about to take a wrong turn with interface identities
Quirin Schroll
qs.il.paperinik at gmail.com
Mon Nov 20 16:41:46 UTC 2023
The [spec on identity
expressions](https://dlang.org/spec/expression.html#identity_expressions) was recently [changed](https://github.com/dlang/dlang.org/pull/3726) 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](https://forum.dlang.org/post/gitvtdwiygpuvwduomfc@forum.dlang.org), 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
More information about the Digitalmars-d
mailing list