Thread overview
template specialization
Jun 08, 2010
Larry Luther
Jun 08, 2010
Simen kjaeraas
Jun 08, 2010
Robert Clipsham
Jun 08, 2010
Ellery Newcomer
Jun 08, 2010
Larry Luther
Jun 09, 2010
Don
Jun 09, 2010
bearophile
Jun 10, 2010
Trass3r
Jun 10, 2010
Larry Luther
June 08, 2010
This code:

import std.stdio;


class A {

  void get (T:ubyte)(T[] buffer) {
    writefln( "get (T:ubyte)(T[] buffer)\n");
  }

  void get (T:byte)(T[] buffer) {
    writefln( "get (T:byte)(T[] buffer)\n");
  }

  void get (T)(T[] buffer) {
    writefln( "get (T)(T[] buffer)\n");
  }
}


void main () {
  A foo = new A;
  ubyte[100] ub;
  byte[100] bb;
  int[100] ib;

  foo.get( ub);
  foo.get( bb);
  foo.get( ib);
}

Generates:

  get (T:ubyte)(T[] buffer)

  get (T:ubyte)(T[] buffer)

  get (T)(T[] buffer)

Note:  If "get(T:byte)" preceeded "get(T:ubyte)" then "get(T:byte)" would be called in both cases.

Q: Is this the way it's supposed to be?

  Thanks, Larry



June 08, 2010
Larry Luther <larry.luther@dolby.com> wrote:

>   get (T:ubyte)(T[] buffer)
>
>   get (T:ubyte)(T[] buffer)
>
>   get (T)(T[] buffer)
>
> Q: Is this the way it's supposed to be?

Looks very much correct, yes. Is there a problem?

-- 
Simen
June 08, 2010
On 08/06/10 22:25, Larry Luther wrote:
> Q: Is this the way it's supposed to be?

Yes, byte implicitly casts to ubyte so it's accepted. Try switching the templates round, they will both be byte. The way around this is to add template constraints to the templates:

void get(T:ubyte)(T[] buffer) if( is( T == ubyte ) ) { }
void get(T:byte)(T[] buffer) if( is( T == byte ) ) { }

etc.

Hope this helps,

Robert
June 08, 2010
On 06/08/2010 05:01 PM, Robert Clipsham wrote:
> On 08/06/10 22:25, Larry Luther wrote:
>> Q: Is this the way it's supposed to be?
>
> Yes, byte implicitly casts to ubyte so it's accepted. Try switching the
> templates round, they will both be byte. The way around this is to add
> template constraints to the templates:
>
> void get(T:ubyte)(T[] buffer) if( is( T == ubyte ) ) { }
> void get(T:byte)(T[] buffer) if( is( T == byte ) ) { }
>
> etc.
>
> Hope this helps,
>
> Robert

bit odd though, since byte[] isn't implicitly convertible to ubyte[].

no wait! yes it is!

void get(T:ubyte[])(T t){}
..
get(new byte[](1));

no wait! no it isn't!

ubyte[] u = new byte[](1);


and is it just me, or does the following silently cast away immutability?

get("hi mom!");
June 08, 2010
Thanks guys.

  Simen asked:  "Is there a problem?".

  Well, I kind of expected a "ubyte" buffer to be matched with a
"get(T:ubyte)".
  I thought methods were searched for the "best" match.

  Larry


June 09, 2010
Larry Luther wrote:
> Thanks guys.
> 
>   Simen asked:  "Is there a problem?".
> 
>   Well, I kind of expected a "ubyte" buffer to be matched with a "get(T:ubyte)".
>   I thought methods were searched for the "best" match.

No, C++ does it that way, and it gets horrendously complicated.
In D, it has to match exactly.
June 09, 2010
On Tue, 08 Jun 2010 17:25:43 -0400, Larry Luther <larry.luther@dolby.com> wrote:

> This code:
>
> import std.stdio;
>
>
> class A {
>
>   void get (T:ubyte)(T[] buffer) {
>     writefln( "get (T:ubyte)(T[] buffer)\n");
>   }
>
>   void get (T:byte)(T[] buffer) {
>     writefln( "get (T:byte)(T[] buffer)\n");
>   }
>
>   void get (T)(T[] buffer) {
>     writefln( "get (T)(T[] buffer)\n");
>   }
> }
>
>
> void main () {
>   A foo = new A;
>   ubyte[100] ub;
>   byte[100] bb;
>   int[100] ib;
>
>   foo.get( ub);
>   foo.get( bb);
>   foo.get( ib);
> }
>
> Generates:
>
>   get (T:ubyte)(T[] buffer)
>
>   get (T:ubyte)(T[] buffer)
>
>   get (T)(T[] buffer)
>
> Note:  If "get(T:byte)" preceeded "get(T:ubyte)" then "get(T:byte)" would be
> called in both cases.
>
> Q: Is this the way it's supposed to be?
>
>   Thanks, Larry


Here is your mistake:

T:U as defined by the spec means any T that implicitly casts to U, not a T that exactly equals U.  Since ubyte and byte implicitly cast to eachother, the first template matches, no matter the order.

But there is a more subtle mistake in what you are doing.

The mistake is here:

> void get (T:ubyte)(T[] buffer) {
>   writefln( "get (T:ubyte)(T[] buffer)\n");
> }

You are assuming that because of this printout, the same instantiation is used.  BUT... The instantiations are different!

You should try this instead:

> void get (T:ubyte)(T[] buffer) {
>   writefln( "get (T:ubyte)(T[] buffer), T == %s\n", T.stringof);
> }

What you will find is the first template is used, but the template parameter T is correctly byte or ubyte depending on the call.

To do what you really want, use template constraints as Robert has suggested.  Before template constraints, the only way to do this properly is to use a static if.

I should also mention that a planned enhancement for the compiler is to make it so this kind of junk isn't necessary, you should just be able to do this:

>   void get (ubyte[] buffer) {
>   }
>
>   void get (byte[] buffer) {
>   }
>
>   void get (T)(T[] buffer) {
>   }

I know this is planned, because it's in TDPL.  BTW, are there any bug reports for this?

-Steve
June 09, 2010
Steven Schveighoffer:
> I know this is planned, because it's in TDPL.  BTW, are there any bug reports for this?

Please write one, overloading of functions with templates is an important and basic thing.

Bye,
bearophile
June 10, 2010
> Please write one, overloading of functions with templates is an important and basic thing.

http://d.puremagic.com/issues/show_bug.cgi?id=3941
June 10, 2010
Thanks everyone.