Is there a way to use Object.factory with templated classes? Or some way to construct templated classes given RTTI of an instance?
Chad Joan
chadjoan at gmail.com
Thu Sep 27 08:44:25 UTC 2018
On Thursday, 27 September 2018 at 08:19:41 UTC, Jonathan M Davis
wrote:
> On Thursday, September 27, 2018 1:41:23 AM MDT Chad Joan via
> Digitalmars-d- learn wrote:
>> On Thursday, 27 September 2018 at 05:12:06 UTC, Jonathan M
>> Davis
>
>> This is also reminding me of how it's always bugged me that
>> there isn't a way to operator overload opEquals with a static
>> method (or even a free function?), given that it would allow
>> the class/struct implementer to guard against (or even
>> interact intelligently with) null values:
>
> That's not really an issue with D. With classes, when you have
> a == b, it
> doesn't lower to a.opEquals(b). Rather, it lowers to
> opEquals(a, b), and the
> free function opEquals is defined as
>
> bool opEquals(Object lhs, Object rhs)
> {
> // If aliased to the same object or both null => equal
> if (lhs is rhs) return true;
>
> // If either is null => non-equal
> if (lhs is null || rhs is null) return false;
>
> // If same exact type => one call to method opEquals
> if (typeid(lhs) is typeid(rhs) ||
> !__ctfe && typeid(lhs).opEquals(typeid(rhs)))
> /* CTFE doesn't like typeid much. 'is' works, but
> opEquals
> doesn't
> (issue 7147). But CTFE also guarantees that equal
> TypeInfos are
> always identical. So, no opEquals needed during
> CTFE. */
> {
> return lhs.opEquals(rhs);
> }
>
> // General case => symmetric calls to method opEquals
> return lhs.opEquals(rhs) && rhs.opEquals(lhs);
> }
>
> /************************
> * Returns true if lhs and rhs are equal.
> */
> bool opEquals(const Object lhs, const Object rhs)
> {
> // A hack for the moment.
> return opEquals(cast()lhs, cast()rhs);
> }
>
> So, it already takes care of checking for null or even if the
> two references point to the same object. For structs, a == b,
> does lower to a.opEquals(b), but for better or worse, structs
> are designed so that their init values need to be valid, or
> you're going to have problems in general. Trying to work around
> that is fighting a losing battle.
>
The spec seems to have the homogeneous cases covered: classes
with classes or structs with structs. What I'm more worried
about is stuff like when you have a class compared to a struct or
builtin type, or maybe a struct compared to a builtin type
(especially more complicated builtin types like arrays!). The
homogeneous cases are important for making a type consistent with
itself, but the other cases are important for integrating a type
with everything else in the ecosystem.
Notably, "alias this" is awesome and has more or less solved that
for me in the pedestrian cases I tend to encounter. I can write
a struct and alias this to some reference variable that will be
representative of my struct's "nullness" or other states of
existence.
But I wouldn't be surprised if there are corner-cases I haven't
encountered yet (actually I think I just remembered that this bit
me a little bit once or twice) where having a single alias-this
isn't sufficient to cover all of the possible things my
struct/class could be compared to (ex: if the type's null-state
corresponded to int.max for ints and float.nan for floats, and
you can't just use opEquals, such as when the type is a class and
could be precisely null).
>> Wouldn't it be helpful to have a root class type just to have
>> a "Top" type at runtime, even if it had no members? Ex: so
>> you could do things like make an array ProtoObject[] foo; that
>> can contain any runtime polymorphic variables.
>
> Maybe? It's not something that I've personally found to be
> particularly
> useful. Once you can templatize code, the need to have a common
> base class
> gets pretty hard to argue for, but I don't know that it's
> non-existent.
> Also, for better or worse, you can already get it with void* -
> and cover
> more types no less (albeit less @safely). But from what I
> understand of what
> Andrei is intending, ProtoObject will end up being the new root
> class for
> all D classos, so having ProtoObject[] would work for all
> extern(D) classes.
> Of course, that still potentially leaves exern(C++) classes and
> interfaces
> (which could be extern(C++) or COM even right now and aren't
> derived from
> Object). So, things are already a bit weird with classes when
> you start
> interacting with other languages through D. is(T : Object) and
> is(T == class) do _not_ mean quite the same thing even though
> you'd think
> that they would. And I haven't done enough with extern(C++) or
> COM in D to
> claim to understand all of the subtleties. If you're not
> messing with them
> directly or writing generic code that's going to mess with
> them, it doesn't
> really matter though.
>
> -Jonathan M Davis
Gotcha. Quite a rabbit hole :)
More information about the Digitalmars-d-learn
mailing list