December 06
https://issues.dlang.org/show_bug.cgi?id=24892

          Issue ID: 24892
           Summary: We need a __traits trait to test for whether one class
                    is derived from another
           Product: D
           Version: D2
          Hardware: All
                OS: All
            Status: NEW
          Severity: enhancement
          Priority: P1
         Component: dmd
          Assignee: nobody@puremagic.com
          Reporter: issues.dlang@jmdavisProg.com

Right now, the normal way to test that one class is derived from another is to do is(T : U), which does not technically test whether T is derived from U. Rather, it tests whether T implicitly converts to U, which happens to be true when T is derived from U. However, it can also be true thanks to alias this, e.g.

```
void main()
{
    auto foo = new Foo;
    A a = foo;

    static assert(is(Foo : A));
}

class A {}

class Foo
{
    A a;

    alias this = a;
}
```

compiles just fine even though Foo is not derived from A. And technically, it's
even possible for is(T : U) and is(U : T) to both be true at the same time
(whether inheritance is involved or not).

As such, we really need to stop testing for inheritance via testing for implicit conversion. While it works most of the time, it is actually wrong and can cause bugs.

There _might_ be some clever way to test whether one class is derived from another by checking whether alias this exists for the class and whether the alias this implicitly converts to the target type in order to exclude it, but then you have the issue that it's possible for the alias this to convert to one of the class' actual base classes, so excluding it could give the wrong answer. As such, I'm not aware of any way to properly test whether a class is actually derived from another - and if it does exist, it's likely to involve several tests when it should just be a simple question.

As such, I would propose that we add something to __traits to provide this information (either that or add something new to is expressions which explicitly tests for it separate from testing for implicit conversions). For instance, we could have __traits(isDerivedFrom, T, U).

Now, that also raises the question of how interfaces should be handled, since arguably, a class is not derived from an interface (rather, it implements it). So, we could also add something like __traits(implements, T, U) - or we could just have __traits(isDerivedFrom, T, U) handle both classes and interfaces and then use is(U == interface) and is(U == class) to distinguish. That being said, separate traits seems simpler, and it makes it so that you don't accidentally treat a class as an interface or vice versa, so that's what I'd vote for.

In either case, given that we're not planning to get rid of alias this and that it seems to make it impossible to properly test whether one class is derived from another, I really think that we should add a way to explicitly test for inheritance to the language, and then we can start using that instead of is(T : U).

--