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