Is there a way to use Object.factory with templated classes? Or some way to construct templated classes given RTTI of an instance?

Jonathan M Davis newsgroup.d at jmdavisprog.com
Thu Sep 27 08:19:41 UTC 2018


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.

> 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





More information about the Digitalmars-d-learn mailing list