www.digitalmars.com         C & C++   DMDScript  

digitalmars.D.learn - Self-referencing template parameters

reply Erik Rasmussen <i_am_erik yahoo.com> writes:
One way that I have found java's generics to be useful is in doing 
something like this:

---
public abstract class Animal<T extends Animal<T>>
{
   public abstract T[] procreate(T mate);
}

public class Monkey extends Animal<Monkey>
{
   public Monkey[] procreate(Monkey mate)
   {
      // make sweet monkey love
   }
}
---

Although you're not strictly forced to by the compiler, if you make it a 
policy to always make your template variable the same as your concrete 
subclass, then you have forced any class that extends Animal to provide 
a way to "procreate" with its own kind.

I seem to be unable to implement this pattern in D.  The following 
doesn't work:

---
abstract class Animal(T : Animal!(T))
{
   abstract T[] procreate(T mate);
}
---

It doesn't like that template definition on the first line.  It says, 
"template instance does not match any template declaration".

Any ideas?

Cheers,
Erik
Mar 20 2006
parent reply Oskar Linde <oskar.lindeREM OVEgmail.com> writes:
Erik Rasmussen skrev:
 One way that I have found java's generics to be useful is in doing 
 something like this:
 
 ---
 public abstract class Animal<T extends Animal<T>>
 {
   public abstract T[] procreate(T mate);
 }
 
 public class Monkey extends Animal<Monkey>
 {
   public Monkey[] procreate(Monkey mate)
   {
      // make sweet monkey love
   }
 }
 ---
 
 Although you're not strictly forced to by the compiler, if you make it a 
 policy to always make your template variable the same as your concrete 
 subclass, then you have forced any class that extends Animal to provide 
 a way to "procreate" with its own kind.
 
 I seem to be unable to implement this pattern in D.  The following 
 doesn't work:
 
 ---
 abstract class Animal(T : Animal!(T))
 {
   abstract T[] procreate(T mate);
 }
 ---
 
 It doesn't like that template definition on the first line.  It says, 
 "template instance does not match any template declaration".
 
 Any ideas?

The problem is that this line contains a recursive instantiation: abstract class Animal(T : Animal!(T)) Animal!(T) has to be instantiated before the compiler knows how to what type it is. But if you place a static assert in a place outside what the compiler needs to deduce the type: class Animal(T) { this() { static assert(is(T : Animal)); } public abstract T[] procreate(T mate); } Things work as they should. /Oskar
Mar 20 2006
parent reply Erik Rasmussen <i_am_erik yahoo.com> writes:
Oskar Linde wrote:
 The problem is that this line contains a recursive instantiation:
 abstract class Animal(T : Animal!(T))
 
 Animal!(T) has to be instantiated before the compiler knows how to what 
 type it is.
 
 But if you place a static assert in a place outside what the compiler 
 needs to deduce the type:
 
 class Animal(T) {
     this() {
         static assert(is(T : Animal));
     }
     public abstract T[] procreate(T mate);
 }
 
 Things work as they should.
 
 
 /Oskar

Thanks, but... test.d --- abstract class Animal(T) { this() { static assert(is(T : Animal)); } public abstract T[] procreate(T mate); } class Monkey : Animal!(Monkey) { public Monkey[] procreate(Monkey mate) { return new Monkey[2]; } } int main(char[][] args) { new Monkey(); } --- When I compile, I get: test.d: variable test.Animal!(Monkey).Animal.this.this abstract cannot be applied to variable test.d:3: variable test.Animal!(Monkey).Animal.this.__result abstract cannot be applied to variable Now what? Line 3 is the "this()" line. Erik
Mar 20 2006
parent Erik Rasmussen <i_am_erik yahoo.com> writes:
Erik Rasmussen wrote:
 Oskar Linde wrote:
 
 The problem is that this line contains a recursive instantiation:
 abstract class Animal(T : Animal!(T))

 Animal!(T) has to be instantiated before the compiler knows how to 
 what type it is.

 But if you place a static assert in a place outside what the compiler 
 needs to deduce the type:

 class Animal(T) {
     this() {
         static assert(is(T : Animal));
     }
     public abstract T[] procreate(T mate);
 }

 Things work as they should.


 /Oskar

Thanks, but... test.d --- abstract class Animal(T) { this() { static assert(is(T : Animal)); } public abstract T[] procreate(T mate); } class Monkey : Animal!(Monkey) { public Monkey[] procreate(Monkey mate) { return new Monkey[2]; } } int main(char[][] args) { new Monkey(); } --- When I compile, I get: test.d: variable test.Animal!(Monkey).Animal.this.this abstract cannot be applied to variable test.d:3: variable test.Animal!(Monkey).Animal.this.__result abstract cannot be applied to variable Now what? Line 3 is the "this()" line. Erik

Oops. The problem was the "abstract" on the very first line. Bad Java habit. Erik
Mar 20 2006