www.digitalmars.com         C & C++   DMDScript  

digitalmars.D.learn - Template design with required type parameters?

reply Charles D Hixson <charleshixsn earthlink.net> writes:
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.
Nov 10 2006
next sibling parent reply "JC" <johnch_atms hotmail.com> writes:
"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?
Nov 10 2006
parent reply Benji Smith <dlanguage benjismith.net> writes:
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
Nov 10 2006
parent reply Benji Smith <dlanguage benjismith.net> writes:
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
Nov 10 2006
parent reply "JC" <johnch_atms hotmail.com> writes:
"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.
Nov 11 2006
parent reply Benji Smith <dlanguage benjismith.net> writes:
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
Nov 12 2006
next sibling parent "JC" <johnch_atms hotmail.com> writes:
"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

Nov 12 2006
prev sibling parent Charles D Hixson <charleshixsn earthlink.net> writes:
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

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.)
Nov 16 2006
prev sibling parent Hasan Aljudy <hasan.aljudy gmail.com> writes:
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
Nov 10 2006