Thread overview
Template design with required type parameters?
Nov 10, 2006
Charles D Hixson
Nov 11, 2006
JC
Nov 11, 2006
Benji Smith
Nov 11, 2006
Benji Smith
Nov 11, 2006
JC
Nov 12, 2006
Benji Smith
Nov 12, 2006
JC
Nov 17, 2006
Charles D Hixson
Nov 11, 2006
Hasan Aljudy
November 10, 2006
Is it possible to design a template that requires, at compile time, that it's parameters be of a particular type?

I.e., that they include a certain class or interface among their ancestry?

What I'm actually contemplating is a kind of "comparable" interface that I want to require one of the parameters to the Template to have.  I haven't decided whether there should be more than one parameter, partially that depends on just how I should approach this.  (I've also considered just skipping templates altogether and doing the entire thing through normal class inheritance...which would work, but everyone seems to be pushing templates right now.)

It's also true that I may just end up doing "duck typing" if the implementation gets too cumbersome.

I'm not really after ultimate run-time efficiency, I'd prefer clarity combined with "good" efficiency.
November 11, 2006
"Charles D Hixson" <charleshixsn@earthlink.net> wrote in message news:ej31kf$1po9$1@digitaldaemon.com...
> Is it possible to design a template that requires, at compile time, that it's parameters be of a particular type?
>
> I.e., that they include a certain class or interface among their ancestry?
>
> What I'm actually contemplating is a kind of "comparable" interface that I want to require one of the parameters to the Template to have.  I haven't decided whether there should be more than one parameter, partially that depends on just how I should approach this.  (I've also considered just skipping templates altogether and doing the entire thing through normal class inheritance...which would work, but everyone seems to be pushing templates right now.)
>
> It's also true that I may just end up doing "duck typing" if the implementation gets too cumbersome.
>
> I'm not really after ultimate run-time efficiency, I'd prefer clarity combined with "good" efficiency.

You can check template types at compile time.

interface ICanDance {
  void dance();
}

class Dancer : ICanDance {
  void dance() {}
}

void goDancing(T)(T o) {
in {
  static if (!is(T : ICanDance)) // check if T is derived from ICanDance
    static assert(false, "Type must be of type 'ICanDance'.");
}
body {
  o.dance();
}

void main() {
  goDancing(null); // triggers the static assertion
  goDancing(new Dancer); // satisfies the type check
}

Is this what you mean?


November 11, 2006
news:ej31kf$1po9$1@digitaldaemon.com...
> Is it possible to design a template that requires, at compile time, that it's parameters be of a particular type?

JC wrote:
> void goDancing(T)(T o) {
> in {
>   static if (!is(T : ICanDance)) // check if T is derived from ICanDance
>     static assert(false, "Type must be of type 'ICanDance'.");
> }
> body {
>   o.dance();
> }

He was probably thinking something along the lines of the C# construct:

  class SortedMap<K, V> where K : IComparable {
    // ...
  }

It looks like the contract & assertion will accomplish the same thing, though not quite as cleanly as the parametric constraint in C#.

--benji
November 11, 2006

Charles D Hixson wrote:
> Is it possible to design a template that requires, at compile time, that it's parameters be of a particular type?
> 
> I.e., that they include a certain class or interface among their ancestry?

//I think this should do it:
template( T : YourParticularType )
{
}
//see http://digitalmars.com/d/template.html
//scroll down to Specialization
November 11, 2006
Benji Smith wrote:
> He was probably thinking something along the lines of the C# construct:
> 
>   class SortedMap<K, V> where K : IComparable {
>     // ...
>   }
> 
> It looks like the contract & assertion will accomplish the same thing, though not quite as cleanly as the parametric constraint in C#.
> 
> --benji

Oops. Looks like I missed the whole section called 'Template Specialization'.

Silly me :^P
November 11, 2006
"Benji Smith" <dlanguage@benjismith.net> wrote in message news:ej3d54$2k2s$1@digitaldaemon.com...
> Benji Smith wrote:
>> He was probably thinking something along the lines of the C# construct:
>>
>>   class SortedMap<K, V> where K : IComparable {
>>     // ...
>>   }
>>
>> It looks like the contract & assertion will accomplish the same thing, though not quite as cleanly as the parametric constraint in C#.

Actually C# sprang to mind when I read the original post. The C# syntax for constraints is very succinct, but quite limited.

>>
>> --benji
>
> Oops. Looks like I missed the whole section called 'Template Specialization'.
>
> Silly me :^P

Specialization is fine for constraining to one type. Type checking is much more flexible. For example, you can check that a type has a certain method, or operator like opAdd (though this doesn't work on basic types).

Also, specializations don't appear to allow you to constrain to enum, struct, class, interface, union, delegate and function, whereas IsExpressions do.

void onlyForEnums(T : enum)(T e) { // error: found 'enum' when expecting ')'
}

void onlyForEnums(T)(T e) {
  static if (!is(T : enum)) static assert(false, "Type not an enum.");
}

John.


November 12, 2006
JC wrote:
> Specialization is fine for constraining to one type. Type checking is much more flexible. For example, you can check that a type has a certain method, or operator like opAdd (though this doesn't work on basic types).
> 
> Also, specializations don't appear to allow you to constrain to enum, struct, class, interface, union, delegate and function, whereas IsExpressions do.
> 
> void onlyForEnums(T : enum)(T e) { // error: found 'enum' when expecting ')'
> }
> 
> void onlyForEnums(T)(T e) {
>   static if (!is(T : enum)) static assert(false, "Type not an enum.");
> }

Excellent points.

One thing in C# that drives me nuts is that you can't do comparisons on primitive values without boxing and unboxing them and using IComparer objects.

>  class BubbleSorter<T> {
>
>    T[] items;
>
>    public BubbleSorter(T[] items) {
>      this.items = items;
>    }
>
>    public T[] sort() {
>      bool needsMoreSorting = true;
>      while (needsMoreSorting) {
>        needsMoreSorting = false;
>        for (int i = 1; i < items.Count; i++) {
>          int prevIndex = i - 1;
>
>          // COMPILE ERROR! You can't use comparison operators with
>          // generic parameters. You must use an IComparer<T> instead.
>
>          if (items[prevIndex] > items[i]) {
>            swap(items, prevIndex, i);
>            needsMoreSorting = true;
>          }
>
>        }
>      }
>      return items;
>    }
>  }

You can fix this by using something like the following:

>  class BubbleSorter<T> where T : IComparable {
>    // ...
>  }

...and then using an IComparer to compare values (instead of the < or > operators). But then you incur the speed penalty of boxing/unboxing, not the mention the relatively high cost of the comparator method call.

Being able to constrain a template like this would be ideal:

>  class BubbleSorter<T> where T implements opCmp {
>    // ...
>  }

Or something like that.

--benji
November 12, 2006
"Benji Smith" <dlanguage@benjismith.net> wrote in message news:ej85jd$ut3$1@digitaldaemon.com...
> One thing in C# that drives me nuts is that you can't do comparisons on primitive values without boxing and unboxing them and using IComparer objects.
>
> >  class BubbleSorter<T> {
> >
> >    T[] items;
> >
> >    public BubbleSorter(T[] items) {
> >      this.items = items;
> >    }
> >
> >    public T[] sort() {
> >      bool needsMoreSorting = true;
> >      while (needsMoreSorting) {
> >        needsMoreSorting = false;
> >        for (int i = 1; i < items.Count; i++) {
> >          int prevIndex = i - 1;
> >
> >          // COMPILE ERROR! You can't use comparison operators with
> >          // generic parameters. You must use an IComparer<T> instead.
> >
> >          if (items[prevIndex] > items[i]) {
> >            swap(items, prevIndex, i);
> >            needsMoreSorting = true;
> >          }
> >
> >        }
> >      }
> >      return items;
> >    }
> >  }
>
> You can fix this by using something like the following:
>
> >  class BubbleSorter<T> where T : IComparable {
> >    // ...
> >  }
>
> ...and then using an IComparer to compare values (instead of the < or > operators). But then you incur the speed penalty of boxing/unboxing, not the mention the relatively high cost of the comparator method call.

Actually, if you use Comparer<T>.Default, and T implements IComparable<T>, you get a Comparer object specialised for that type which avoids boxing and unboxing.

>
> Being able to constrain a template like this would be ideal:
>
> >  class BubbleSorter<T> where T implements opCmp {
> >    // ...
> >  }
>
> Or something like that.
>
> --benji


November 17, 2006
Benji Smith wrote:
> JC wrote:
>> Specialization is fine for constraining to one type. Type checking is much more flexible. For example, you can check that a type has a certain method, or operator like opAdd (though this doesn't work on basic types).
>>
>> Also, specializations don't appear to allow you to constrain to enum, struct, class, interface, union, delegate and function, whereas IsExpressions do.
>>
>> void onlyForEnums(T : enum)(T e) { // error: found 'enum' when expecting ')'
>> }
>>
>> void onlyForEnums(T)(T e) {
>>   static if (!is(T : enum)) static assert(false, "Type not an enum.");
>> }
> 
> Excellent points.
> 
> One thing in C# that drives me nuts is that you can't do comparisons on primitive values without boxing and unboxing them and using IComparer objects.
> 
>  >  class BubbleSorter<T> {
>  >
>  >    T[] items;
>  >
>  >    public BubbleSorter(T[] items) {
>  >      this.items = items;
>  >    }
>  >
>  >    public T[] sort() {
>  >      bool needsMoreSorting = true;
>  >      while (needsMoreSorting) {
>  >        needsMoreSorting = false;
>  >        for (int i = 1; i < items.Count; i++) {
>  >          int prevIndex = i - 1;
>  >
>  >          // COMPILE ERROR! You can't use comparison operators with
>  >          // generic parameters. You must use an IComparer<T> instead.
>  >
>  >          if (items[prevIndex] > items[i]) {
>  >            swap(items, prevIndex, i);
>  >            needsMoreSorting = true;
>  >          }
>  >
>  >        }
>  >      }
>  >      return items;
>  >    }
>  >  }
> 
> You can fix this by using something like the following:
> 
>  >  class BubbleSorter<T> where T : IComparable {
>  >    // ...
>  >  }
> 
> ...and then using an IComparer to compare values (instead of the < or > operators). But then you incur the speed penalty of boxing/unboxing, not the mention the relatively high cost of the comparator method call.
> 
> Being able to constrain a template like this would be ideal:
> 
>  >  class BubbleSorter<T> where T implements opCmp {
>  >    // ...
>  >  }
> 
> Or something like that.
> 
> --benji
Yes, that's what I meant.  I take it that one can do:
class BubbleSorter<T> where T : IComparable {
but not:
class BubbleSorter<T> where T implements opCmp {

(The second would be nicer in general, but I was really asking about the first.  I can define an interface to contain just the functions that I need to have matched.)

Thanks to all!
(I missed the section on Template Specialization also.)