Inheritance of things that are note instance methods

Arafel via Digitalmars-d digitalmars-d at puremagic.com
Thu Aug 3 05:06:02 PDT 2017


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/olng6h$1e1s$1@digitalmars.com
[3]: https://forum.dlang.org/thread/axpqehyrvunzcjnrdccn@forum.dlang.org


More information about the Digitalmars-d mailing list