www.digitalmars.com         C & C++   DMDScript  

digitalmars.D.learn - Templated class defaults and inheritence

reply Joerg Joergonson <JJoergonson gmail.com> writes:
I have something like

class X;
class subfoo : X;
class subbaz : X;

class foo : X
{
     subfoo bar;
}

class baz : X;


which I have modified so that

class subbaz : subfoo;
class baz : foo;

(essentially baz is now a derivation of foo while before it was 
of X)

the problem is that subbaz uses subfoo bar; when it also needs to 
use a derived type. (so it is a full derivation of foo and subfoo)


To accomplish that I parameterized foo so I can do

class foo!T : X
{
     T bar;
}


and I can now do

class baz : foo!subbaz;


There are two problems with this though:


1. How can I create a default foo!(T = subfoo) so I can just 
instantiate classes like new foo() and it is the same as 
foo!subfoo()? I tried creating a class like class foo : 
foo!subfoo; but I get a collision. I guess an alias will work 
here just fine though?(just thought of it)

2. The real problem is that baz isn't really a true derivation of 
foo like it should be. foo!subfoo and foo!subbaz are different 
types. I want the compiler to realize that foo!subbaz(and hence 
baz) is really a derived foo!subfoo and ultimately X.

I'm pretty sure D can do this, just haven't figure out how.

Thanks.
Jun 17 2016
next sibling parent reply Klaus Kalsesh <kk mqsldkmlsdkgq.se> writes:
On Saturday, 18 June 2016 at 02:11:23 UTC, Joerg Joergonson wrote:
 I have something like

 class X;
 class subfoo : X;
 class subbaz : X;

 class foo : X
 {
     subfoo bar;
 }

 class baz : X;


 which I have modified so that

 class subbaz : subfoo;
 class baz : foo;

 (essentially baz is now a derivation of foo while before it was 
 of X)

 the problem is that subbaz uses subfoo bar; when it also needs 
 to use a derived type. (so it is a full derivation of foo and 
 subfoo)


 To accomplish that I parameterized foo so I can do

 class foo!T : X
 {
     T bar;
 }


 and I can now do

 class baz : foo!subbaz;


 There are two problems with this though:


 1. How can I create a default foo!(T = subfoo) so I can just 
 instantiate classes like new foo() and it is the same as 
 foo!subfoo()? I tried creating a class like class foo : 
 foo!subfoo; but I get a collision. I guess an alias will work 
 here just fine though?(just thought of it)
You must declare an alias: alias FooSubfoo = foo!subfoo; FooSubfoo fsf = new FooSubfoo;
 2. The real problem is that baz isn't really a true derivation 
 of foo like it should be. foo!subfoo and foo!subbaz are 
 different types. I want the compiler to realize that 
 foo!subbaz(and hence baz) is really a derived foo!subfoo and 
 ultimately X.
For multiple inheritence in classes, the standard way of doing is with interfaces. So instead of a template: class foo: interfaceThis, interfaceThat {} alias this can work too but there only can be one: class foo!T : X { T bar; alias bar this; } This pattern is called the "Curiously recurring template" BTW. With the alias this it's almost usable, which was not the case in the original form (because you have an indirection to access the derived type that's indicated by the template parameter. Actually from the machine code POV it's still the case but in the source code it's hidden by the alias this shortcut.
Jun 18 2016
parent Joerg Joergonson <JJoergonson gmail.com> writes:
On Saturday, 18 June 2016 at 12:15:56 UTC, Klaus Kalsesh wrote:
 On Saturday, 18 June 2016 at 02:11:23 UTC, Joerg Joergonson 
 wrote:
 I have something like

 class X;
 class subfoo : X;
 class subbaz : X;

 class foo : X
 {
     subfoo bar;
 }

 class baz : X;


 which I have modified so that

 class subbaz : subfoo;
 class baz : foo;

 (essentially baz is now a derivation of foo while before it 
 was of X)

 the problem is that subbaz uses subfoo bar; when it also needs 
 to use a derived type. (so it is a full derivation of foo and 
 subfoo)


 To accomplish that I parameterized foo so I can do

 class foo!T : X
 {
     T bar;
 }


 and I can now do

 class baz : foo!subbaz;


 There are two problems with this though:


 1. How can I create a default foo!(T = subfoo) so I can just 
 instantiate classes like new foo() and it is the same as 
 foo!subfoo()? I tried creating a class like class foo : 
 foo!subfoo; but I get a collision. I guess an alias will work 
 here just fine though?(just thought of it)
You must declare an alias: alias FooSubfoo = foo!subfoo; FooSubfoo fsf = new FooSubfoo;
No, this is not what I'm asking I would want something like alias foo = foo!subfoo; Not sure, though, if a when I instantiate like new foo(); If the compiler will understand it is new foo!subfoo(); I see no problem here but haven't tested it.
 2. The real problem is that baz isn't really a true derivation 
 of foo like it should be. foo!subfoo and foo!subbaz are 
 different types. I want the compiler to realize that 
 foo!subbaz(and hence baz) is really a derived foo!subfoo and 
 ultimately X.
For multiple inheritence in classes, the standard way of doing is with interfaces.
This is not multiple inheritance and alias this won't work. Let me explain better: X -> foo%subfoo -> baz%subbaz by -> I mean inherits and by %, I mean "uses"(say, as a field or method parameter or whatever) This then says that foo uses subfoo and is derived from X. Similarly for baz. These are two distinct types(hence the two different lines) Now, if baz inherits from foo instead of X, we have X -> foo%subfoo -> baz%subfoo But if subfoo -> subbaz, then we should be able to do X -> foo%subfoo -> (baz%subfoo) -> baz%subbaz. Note the are now on the same line. baz%subbaz is a derived type of foo%subfoo, not just X as in the first two line case. This is an important distinction in the type system. It's sort of multiple inheritance in that multiple types are used but each type only inherits once. In C# we have the "where" keyword that lets us tell the compiler something like "where subbaz inherits from subfoo". Dlang once had a page that had ways to express stuff like this but I can no longer find it ;/ It might be a syntax like class baz!T : foo!(T : subfoo); which may say "T must be derived from subfoo". Then baz!subbaz would work and it would be a derived type of foo!subfoo(rather than just X).
Jun 18 2016
prev sibling parent reply Joerg Joergonson <JJoergonson gmail.com> writes:
This is solved through simple inheritance constraints and 
aliasing with qualification.


class X;
class subfoo;
class subbaz : subfoo;
class foo(T) if (is(T : subfoo)) X;
class baz(T) if (is(T : subbaz)) foo!T;

then when we need foo with "default",

alias foo = qualified.foo!subfoo;

Without the qualification, which I guess requires having this 
stuff in a separate module, there is no conflict. alias foo = 
foo!subfoo; fails circularly.
Jun 18 2016
parent Rene Zwanenburg <renezwanenburg gmail.com> writes:
On Saturday, 18 June 2016 at 17:48:47 UTC, Joerg Joergonson wrote:
 class foo(T) if (is(T : subfoo)) X;
FYI this can also be done in the template parameter list: class foo(T : subfoo){}
Jun 19 2016