Hi!

TL;DR: Inheritance seems to be a mess out of instance methods. Some things work, some other don't or not as expected, and apparently it isn't documented either [1].

Does somebody know how it's even *supposed* to work? Making it a bit more intuitive would also be nice :-)

Now, the long rant:

----

After a couple of threads in learn [2,3] related to how inheritance works in D out of the "usual" case of instance methods, I haven't been able to find in the spec [1] how things are supposed to be, and indeed I find the situation quite messy:

* Static functions are "virtual", i.e. there is a lookup of parent classes if it's not found. This is not documented, and I didn't even think it would work:

```
class A {
        static void foo() { };
}

class B : A { }

void main() {
        B.foo(); // This works, surprisingly
}
```

* However, there's no way for B.foo() to get its own class:

```
class A {
        static void foo() {
                import std.stdio;

                writeln(typeid(typeof(this)));
        }
}

class B : A { }

void main() {
        B.foo(); // This prints "A", I'd like to print "B"
}
```

This is a bit shocking, since the compiler must know for sure which class I'm from, and I can also make it explicit:

```
class A {
        static void foo(C)() {
                import std.stdio;

                writeln(typeid(C));
        }
}

class B : A { }

alias foo(C : A) = C.foo!C;

void main() {
        foo!B(); // This does indeed print "B"
}
```

I'd argue that since it's *already possible* (just inconvenient, unintuitive, and convoluted), "this" template parameters should be available everywhere, thus making something like this work out of the box:

```
class A {
        static void foo(this C)() {
                import std.stdio;

                writeln(typeid(typeof(this)));
                writeln(typeid(C));
        }
}

class B : A { }

void main() {
        B.foo(); // This should print "A" and then "B"
}
```

I think this is how most people would expect it to work, *given that B.foo() already works*. The other option would be to totally disable looking up static functions of parent classes.

* Finally, things get even more confusing with templates: a missing template will be looked up in "parent" classes, but a template that exists but is not instantiable won't:

```
class A {
        template foo(string s) if (s == "bar") {
                enum foo = 1;
        }
        enum bar = 1;
        
}

class B : A {
        template foo(string s) if (s == "baz") {
                enum foo = 2;
        }
        enum baz = 2;
}

void main() {
        import std.stdio;
        
        writeln(B.bar); // This works: bar is taken from A
        writeln(B.baz); // This also works, baz is directly in B
        //writeln(B.foo!"bar"); // This doesn't work: why?
        writeln(B.foo!"baz");
}
```

So all in all, I think it'd be nice to have some clear spec on what is supposed to work or not, and I also think that with just a couple of small changes things might greatly improve.

A.

[1]: https://dlang.org/spec/class.html
[2]: https://forum.dlang.org/post/[email protected]
[3]: https://forum.dlang.org/thread/[email protected]

Reply via email to