Thread overview
Self-referencing template parameters
Mar 20, 2006
Erik Rasmussen
Mar 20, 2006
Oskar Linde
Mar 20, 2006
Erik Rasmussen
Mar 20, 2006
Erik Rasmussen
March 20, 2006
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
March 20, 2006
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
March 20, 2006
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
March 20, 2006
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