www.digitalmars.com         C & C++   DMDScript  

digitalmars.D.learn - template specialization question

reply daoryn <manse fots.po> writes:
According to http://digitalmars.com/d/2.0/template.html it is possible to
specify template specialization so that DMD prefers them when instanciating
templates, however the following code:


---------------------------------
import std.stdio;

void print(T)(T thing)
{
	writeln("Calling print(T)");
	writeln(T.stringof);
}

void print(T:T[])(T[] things)
{
	writeln("Calling print(T[])");
	writeln(T.stringof);
}

void main()
{
	print(3);
	print([1,2,3]);
}

-----------------------------------------

will output:

Calling print(T)
int
Calling print(T)
int[3u]

I expected it to output "calling print(T[])" on the second "print". Would this
be a bug or did I misunderstand the template specialization?
Jan 31 2010
next sibling parent reply Daniel Murphy <yebbliesnospam gmail.com> writes:
daoryn Wrote:

 According to http://digitalmars.com/d/2.0/template.html it is possible to
specify template specialization so that DMD prefers them when instanciating
templates, however the following code:
 
 
 ---------------------------------
 import std.stdio;
 
 void print(T)(T thing)
 {
 	writeln("Calling print(T)");
 	writeln(T.stringof);
 }
 
 void print(T:T[])(T[] things)
 {
 	writeln("Calling print(T[])");
 	writeln(T.stringof);
 }
 
 void main()
 {
 	print(3);
 	print([1,2,3]);
 }
 
 -----------------------------------------
 
 will output:
 
 Calling print(T)
 int
 Calling print(T)
 int[3u]
 
 I expected it to output "calling print(T[])" on the second "print". Would this
be a bug or did I misunderstand the template specialization?
 

It looks like the type of the array literal is a static array, not a dynamic one. Static arrays can be matched with the following specification: void print(T : U[N], U, size_t N)(T things) Or you could use the slice operator to transform the static array into a dynamic one. eg print([1,2,3][]);
Jan 31 2010
parent daoryn <poreas asiot.po> writes:
Daniel Murphy Wrote:

 daoryn Wrote:
 
 According to http://digitalmars.com/d/2.0/template.html it is possible to
specify template specialization so that DMD prefers them when instanciating
templates, however the following code:
 
 
 ---------------------------------
 import std.stdio;
 
 void print(T)(T thing)
 {
 	writeln("Calling print(T)");
 	writeln(T.stringof);
 }
 
 void print(T:T[])(T[] things)
 {
 	writeln("Calling print(T[])");
 	writeln(T.stringof);
 }
 
 void main()
 {
 	print(3);
 	print([1,2,3]);
 }
 
 -----------------------------------------
 
 will output:
 
 Calling print(T)
 int
 Calling print(T)
 int[3u]
 
 I expected it to output "calling print(T[])" on the second "print". Would this
be a bug or did I misunderstand the template specialization?
 

It looks like the type of the array literal is a static array, not a dynamic one. Static arrays can be matched with the following specification: void print(T : U[N], U, size_t N)(T things) Or you could use the slice operator to transform the static array into a dynamic one. eg print([1,2,3][]);

Sadly, your solution doesnt apply. The used template is still the wrong one. Code: void print(T)(T thing) { writeln("Calling print(T)"); writeln(T.stringof); } void print(T:T[])(T[] things) { writeln("Calling print(T[])"); writeln(T.stringof); } void main() { print(3); print([1,2,3][]); } --------------- output: Calling print(T) int Calling print(T) int[] NOTE: DMD2.040 used.
Feb 01 2010
prev sibling next sibling parent reply Ellery Newcomer <ellery-newcomer utulsa.edu> writes:
I haven't gotten around to templates yet, so I don't grok them quite as 
well as I'd like, but it looks like DMD is having trouble deducing T 
from the parameter given.

print([1,2,3]) fails to match the specialized template, even when the 
general template is removed.

If you force the template parameter, it does what you would expect:


	print!(int)(3);
	print!(int[3])([1,2,3]);


Calling print(T)
int
Calling print(T[])
int

Can't say whether this belongs in bugzilla or not. It might.

On 01/31/2010 12:49 PM, daoryn wrote:

 I expected it to output "calling print(T[])" on the second "print". Would this
be a bug or did I misunderstand the template specialization?

Jan 31 2010
parent reply daoryn <poreas asiot.po> writes:
Ellery Newcomer Wrote:

 I haven't gotten around to templates yet, so I don't grok them quite as 
 well as I'd like, but it looks like DMD is having trouble deducing T 
 from the parameter given.
 
 print([1,2,3]) fails to match the specialized template, even when the 
 general template is removed.
 
 If you force the template parameter, it does what you would expect:
 
 
 	print!(int)(3);
 	print!(int[3])([1,2,3]);
 
 
 Calling print(T)
 int
 Calling print(T[])
 int
 
 Can't say whether this belongs in bugzilla or not. It might.
 
 On 01/31/2010 12:49 PM, daoryn wrote:
 
 I expected it to output "calling print(T[])" on the second "print". Would this
be a bug or did I misunderstand the template specialization?


The whole point of specialisation (and of templates in general) is to have functions that work for any type. Having to forcibly specify a type is like casting to a specific overload of a function. Why add clutter to the syntax when the language advertises automatic type inference?
Feb 01 2010
parent Ellery Newcomer <ellery-newcomer utulsa.edu> writes:
On 02/01/2010 04:19 PM, daoryn wrote:
 The whole point of specialisation (and of templates in general) is to have
functions that work for any type. Having to forcibly specify a type is like
casting to a specific overload of a function. Why add clutter to the syntax
when the language advertises automatic type inference?

I disagree. The whole point of specialization is to isolate specific cases that you want to handle differently. The point of templates (probably not in whole) is to parameterize types. The point of argument deduction is, as you put it, to have functions that work for any type. I do agree that you shouldn't be having any problem whatsoever, but my previous example illustrated that specialization is not at fault. DMD just can't deduce what T is given the argument either because the syntax logically doesn't make sense, or because DMD is retarded. try compiling the following: import std.stdio; void print(T:T[])(T[] thing){ writeln("Calling print(T[])"); writeln(T.stringof); } void main() { print([1,2,3]); } it gives me: test.d(8): Error: template test.print(T : T[]) does not match any function template declaration test.d(8): Error: template test.print(T : T[]) cannot deduce template function from argument types !()(int[3u])
Feb 01 2010
prev sibling next sibling parent reply =?iso-8859-2?B?VG9tZWsgU293afFza2k=?= <just ask.me> writes:
Dnia 31-01-2010 o 19:49:44 daoryn <manse fots.po> napisa=B3(a):

 import std.stdio;
 void print(T)(T thing)
 {
 	writeln("Calling print(T)");
 	writeln(T.stringof);
 }
 void print(T:T[])(T[] things)
 {
 	writeln("Calling print(T[])");
 	writeln(T.stringof);
 }
 void main()
 {
 	print(3);
 	print([1,2,3]);
 }

I'd say it should be more like: // specialization needed to limit matching types void print(T:int)(T thing) { writeln("Calling print(T)"); writeln(T.stringof); } // T is an array of any Us. void print(T:U[], U)(T things) { writeln("Calling print(T[])"); writeln(T.stringof); } Tomek
Jan 31 2010
next sibling parent reply =?iso-8859-2?B?VG9tZWsgU293afFza2k=?= <just ask.me> writes:
Dnia 31-01-2010 o 20:59:47 Tomek Sowi=F1ski <just ask.me> napisa=B3(a):

 // specialization needed to limit matching types
 void print(T:int)(T thing)

To be clear -- I did this to silence the compiler saying the call with = array matches more than one function template declaration. I'm not sure = = whether the compiler is right -- it has a print specifically for arrays = so = it should be picked over plain print(T) as it's more specialized... any = = template expert here? Tomek
Jan 31 2010
parent reply =?UTF-8?B?QWxpIMOHZWhyZWxp?= <acehreli yahoo.com> writes:
� wrote:
 Dnia 31-01-2010 o 20:59:47 Tomek Sowi�ski <just ask.me> napisa�(a):
 
 // specialization needed to limit matching types
 void print(T:int)(T thing)

To be clear -- I did this to silence the compiler saying the call with array matches more than one function template declaration. I'm not sure whether the compiler is right -- it has a print specifically for arrays so it should be picked over plain print(T) as it's more specialized... any template expert here? Tomek

It works with dmd 2.040 without the :int specialization. Also, for variety, i've used the 'is' expression as described here http://digitalmars.com/d/2.0/expression.html#IsExpression for "conditional compilation" in the program below. I think specialization vs. conditional compilation differ semantically this way (no expert here! :) ): specialization: Use this definition for T matching U[] is expression: Consider this definition only for T matching U[] The effect should be the same in this case; but it feels like there must be a difference. :) import std.stdio; void print(T)(T thing) { writeln("Calling print(T)"); writeln(T.stringof); } // T is an array of any Us. void print(T, U)(T things) if (is (T == U[])) // <-- is expression { writeln("Calling print(T[])"); writeln(T.stringof); } void main() { print(3); print([1,2,3]); } Also it could be is (T : U[]) as well, which differs from is (T == U[]) as explained at the link above. Ali
Jan 31 2010
next sibling parent daoryn <poreas asiot.po> writes:
 It works with dmd 2.040 without the :int specialization.

No it doesnt. Did you use specific compiler flags? Also check that you are using the source I posted and not the modified versions presented which served only to circumvent compiler warnings and not answer the original question: is it a compiler bug or misinterpreted template specialization?
Feb 01 2010
prev sibling parent daoryn <poreas asiot.po> writes:
Tomek Sowiński Wrote:

 Dnia 31-01-2010 o 21:39:21 Ali Çehreli <acehreli yahoo.com> napisał(a):
 
 � wrote:
 Dnia 31-01-2010 o 20:59:47 Tomek Sowi�ski <just ask.me> napisa�(a):

 // specialization needed to limit matching types
 void print(T:int)(T thing)

array matches more than one function template declaration. I'm not sure whether the compiler is right -- it has a print specifically for arrays so it should be picked over plain print(T) as it's more specialized... any template expert here? Tomek

It works with dmd 2.040 without the :int specialization.

It's high time I upgraded, then.
 Also, for variety, i've used the 'is' expression as described here

    http://digitalmars.com/d/2.0/expression.html#IsExpression

 for "conditional compilation" in the program below. I think  
 specialization vs. conditional compilation differ semantically this way  
 (no expert here! :) ):

 specialization: Use this definition for T matching U[]

 is expression: Consider this definition only for T matching U[]

 The effect should be the same in this case; but it feels like there must  
 be a difference. :)

 import std.stdio;

 void print(T)(T thing)
 {
      writeln("Calling print(T)");
      writeln(T.stringof);
 }

 // T is an array of any Us.
 void print(T, U)(T things)
      if (is (T == U[]))               // <-- is expression
 {
      writeln("Calling print(T[])");
      writeln(T.stringof);
 }

 void main()
 {
      print(3);
      print([1,2,3]);
 }

 Also it could be is (T : U[]) as well, which differs from is (T == U[])  
 as explained at the link above.

 Ali

Or even simpler: void print(T)(T[] things) But that's "regular" not template overloading. Tomek

The "is" solution is simpler if one uses the "isArray!()" from std.traits. The function can then be correctly implemented but the original issue remains: is it a compiler bug or misinterpretation of the spec? Adding an additional hidden type is just awkward when simpler solutions exist (and are advertised on the spec). Why go into the clutter of conditional compilation if simple template overloading should work?
Feb 01 2010
prev sibling parent =?utf-8?B?VG9tZWsgU293acWEc2tp?= <just ask.me> writes:
Dnia 31-01-2010 o 21:39:21 Ali =C3=87ehreli <acehreli yahoo.com> napisa=C5=
=82(a):

 =EF=BF=BD wrote:
 Dnia 31-01-2010 o 20:59:47 Tomek Sowi=EF=BF=BDski <just ask.me> napis=


 // specialization needed to limit matching types
 void print(T:int)(T thing)



 array matches more than one function template declaration. I'm not su=


 whether the compiler is right -- it has a print specifically for arra=


 so it should be picked over plain print(T) as it's more specialized..=


 any template expert here?
   Tomek

It works with dmd 2.040 without the :int specialization.

It's high time I upgraded, then.
 Also, for variety, i've used the 'is' expression as described here

    http://digitalmars.com/d/2.0/expression.html#IsExpression

 for "conditional compilation" in the program below. I think  =

 specialization vs. conditional compilation differ semantically this wa=

 (no expert here! :) ):

 specialization: Use this definition for T matching U[]

 is expression: Consider this definition only for T matching U[]

 The effect should be the same in this case; but it feels like there mu=

 be a difference. :)

 import std.stdio;

 void print(T)(T thing)
 {
      writeln("Calling print(T)");
      writeln(T.stringof);
 }

 // T is an array of any Us.
 void print(T, U)(T things)
      if (is (T =3D=3D U[]))               // <-- is expression
 {
      writeln("Calling print(T[])");
      writeln(T.stringof);
 }

 void main()
 {
      print(3);
      print([1,2,3]);
 }

 Also it could be is (T : U[]) as well, which differs from is (T =3D=3D=

 as explained at the link above.

 Ali

Or even simpler: void print(T)(T[] things) But that's "regular" not template overloading. Tomek
Jan 31 2010
prev sibling parent reply =?UTF-8?B?QWxpIMOHZWhyZWxp?= <acehreli yahoo.com> writes:
daoryn wrote:
 According to http://digitalmars.com/d/2.0/template.html it is 

when instanciating templates, however the following code:
 ---------------------------------
 import std.stdio;

 void print(T)(T thing)
 {
 	writeln("Calling print(T)");
 	writeln(T.stringof);
 }

 void print(T:T[])(T[] things)

Regardless of the intent of the document, which may very well be outdated or wrong at this time; the specialization above is confusing. If (T:T[]) is supposed to mean "array type", then the function parameter 'T[] things' above would mean "array of array". i.e. If T is T[], then the parameter is T[][]... For that reason this is more logical to me, and I would expect it to be sufficient to express the specialization: void print(T:T[])(T things) But it still selects the general definition above... I don't know... :) Ali
Feb 01 2010
parent Ellery Newcomer <ellery-newcomer utulsa.edu> writes:
On 02/01/2010 07:29 PM, Ali Çehreli wrote:
 daoryn wrote:
  > According to http://digitalmars.com/d/2.0/template.html it is
 possible to specify template specialization so that DMD prefers them
 when instanciating templates, however the following code:
  >
  >
  > ---------------------------------
  > import std.stdio;
  >
  > void print(T)(T thing)
  > {
  > writeln("Calling print(T)");
  > writeln(T.stringof);
  > }
  >
  > void print(T:T[])(T[] things)

 Regardless of the intent of the document, which may very well be
 outdated or wrong at this time; the specialization above is confusing.

It is.
 If (T:T[]) is supposed to mean "array type", then the function parameter
 'T[] things' above would mean "array of array". i.e. If T is T[], then
 the parameter is T[][]...

I wondered that too. I think what happens is the type is matched to T[], and not T, and then it figures out from there what T should be, so that T[] in the function parameter is the same as the type passed in.
 For that reason this is more logical to me, and I would expect it to be
 sufficient to express the specialization:

 void print(T:T[])(T things)

 But it still selects the general definition above...

 I don't know... :)

 Ali

Feb 01 2010