Thread overview
template fiddling
Aug 07, 2010
Blonder
Aug 07, 2010
Mafi
Aug 07, 2010
Blonder
Aug 07, 2010
Dmitry Olshansky
Aug 07, 2010
bearophile
Aug 08, 2010
Blonder
Aug 07, 2010
Mafi
August 07, 2010
Hello,

I am trying to understand the template mechanism in D, but I don't get it working.

I want to compute the dot product as follows:
	int[] a = [1, 2, 3];
	int[] b = [5, 6, 7];

	double dd = ???.dot_product( a, b );

with classes like this:
class DotProduct(DIM, T)
{
	static T result(T a, T b)
	{
		return a * b + DotProduct!(DIM-1, T).result(a+1, b+1);
	}
}

class DotProduct(1, T)
{
	static T result(T a, T b)
	{
		return a * b;
	}
}

and a function :
T dot_product(DIM a, T b)
{
  return ???.result( a, b );
}

Can anyone help me? In C++ its not the problem but with D I can't get it working.

Thanks,
Andreas
August 07, 2010
Am 07.08.2010 18:40, schrieb Blonder:
> Hello,
>
> I am trying to understand the template mechanism in D, but I don't get it working.
>
> I want to compute the dot product as follows:
> 	int[] a = [1, 2, 3];
> 	int[] b = [5, 6, 7];
>
> 	double dd = ???.dot_product( a, b );
>
> with classes like this:
> class DotProduct(DIM, T)
> {
> 	static T result(T a, T b)
> 	{
> 		return a * b + DotProduct!(DIM-1, T).result(a+1, b+1);
> 	}
> }
>
> class DotProduct(1, T)
> {
> 	static T result(T a, T b)
> 	{
> 		return a * b;
> 	}
> }
>
> and a function :
> T dot_product(DIM a, T b)
> {
>    return ???.result( a, b );
> }
>
> Can anyone help me? In C++ its not the problem but with D I can't
> get it working.
>
> Thanks,
> Andreas

Hi,
to make an instance of an template you use the !-infix operator: 'template!(param,...)'. If you want to give only one parameter you can use 'template!param'. But your example can't work because template arguments have to be evaluatable at compile time (which function parameters are not). You can use a normal function parameter.

In your example you use a template class which isn't supposed to be used as class, I think. If so, you should make a simple template
template MyTemplate(.......){
  int myFunction(....){}
  int myFunction2(....){}
}
Then you can say MyTemplate!(...).myFunction(...). You can leave out tralling template arguments which deducable by the arguments of the function.

There also a trick that you can use to make a shortcut. Add
  alias MyTemplate myFunction
to the template. Then you can use MyTemplate!(....)(....)instead of MyTemplate!(.....).myFunction(....). MyTemplate!(....).myFunction2(....) will still work.

The above trick is also how class and function templates work.

Mafi


P.S. If you often use some template instance you can use an alias
  alias MyTemplate!(.....) MyInstance
August 07, 2010
Hello,
the template!(...) mechanism I understand.
But I think I need the two classes, the first is the primary template
and the second the partial specialization (this is the end of the "loop"), or can
I do this in D with functions?

The normal computation of the dot product is normally done in a for loop. But with
templates you can enroll the loop.
template!(...)(3, a, b). In this example 3 is the dimension of the arrays a and b.

Andreas.
August 07, 2010
On 07.08.2010 23:04, Blonder wrote:
> Hello,
> the template!(...) mechanism I understand.
> But I think I need the two classes, the first is the primary template
> and the second the partial specialization (this is the end of the "loop"), or can
> I do this in D with functions?
>
> The normal computation of the dot product is normally done in a for loop. But with
> templates you can enroll the loop.
> template!(...)(3, a, b). In this example 3 is the dimension of the arrays a and b.
>
>    
Probably, this could be a starting point (BTW  In D you can write templates very easy):

T dot_product(size_t N, T)(T[] a, T[] b){
    static if (N == 1){
        return a[0] * b[0];
    }else{
        return a[0] * b[0] + dot_product!(N-1)(a[1..$],b[1..$]);
    }
}

void main()
{
    int[] a = [1, 2, 3];
    int[] b = [5, 6, 7];
    assert( dot_product!3(a,b) == 38 );//sanity check
}
And I didn't checked the disassembly.
> Andreas.
>    


-- 
Dmitry Olshansky

August 07, 2010
Am 07.08.2010 21:04, schrieb Blonder:
> Hello,
> the template!(...) mechanism I understand.
> But I think I need the two classes, the first is the primary template
> and the second the partial specialization (this is the end of the "loop"), or can
> I do this in D with functions?
>
> The normal computation of the dot product is normally done in a for loop. But with
> templates you can enroll the loop.
> template!(...)(3, a, b). In this example 3 is the dimension of the arrays a and b.
>
> Andreas.
Is that what you are searching for:
/////////////
module templatetest;

import std.stdio;

T[] foo(T : T[], int S) (T[] t) {
  writeln("Hey ",S);
  return foo!(T[],S-1)(t);
}

T[] foo(T : T[], int S : 0) (T[] t) {
  writeln("END");
  return(t);
}

/*
//Can't get static arrays right
//always uses dynamic version
T[S] foo(T : T[S], int S) (T[S] t) {
  writeln("Hello ",S);
  return foo!(T[],S-1)(t);
}

T[S] foo(T : T[S], int S:0) (T[S] t) {
  writeln("END2");
}*/

void main() {
  int[] x = [25,42,26,34,10];
  foo!(int[],5)(x);
}
//////////////
Uage foo!(int[],5)(xy). If you swap around the array parameters in your version then you should be able to omit T.
Also when you have fixed-size arrays the array length isn't DRY.
August 07, 2010
Dmitry Olshansky:
> Probably, this could be a starting point (BTW  In D you can write templates very easy):
> 
> T dot_product(size_t N, T)(T[] a, T[] b){
>      static if (N == 1){
>          return a[0] * b[0];
>      }else{
>          return a[0] * b[0] + dot_product!(N-1)(a[1..$],b[1..$]);
>      }
> }
> 
> void main()
> {
>      int[] a = [1, 2, 3];
>      int[] b = [5, 6, 7];
>      assert( dot_product!3(a,b) == 38 );//sanity check
> }
> And I didn't checked the disassembly.

I have added another version:

import std.typetuple: TypeTuple;

T dot_product(size_t N, T)(T[] a, T[] b) {
     static if (N == 1)
         return a[0] * b[0];
     else
         return a[0] * b[0] + dot_product!(N-1)(a[1..$],b[1..$]);
}

template Iota(int stop) {
    static if (stop <= 0)
        alias TypeTuple!() Iota;
    else
        alias TypeTuple!(Iota!(stop-1), stop-1) Iota;
}

T dotProduct(T, int N)(T[N] a, T[N] b) {
    T result = 0;
    foreach (i; Iota!(N))
        result += a[i] * b[i];
    return result;
}

void main() {
    double[3] a = [1., 2., 3.];
    double[3] b = [5., 6., 7.];
    assert(dot_product!3(a, b) == 38.0);
    assert(dotProduct(a, b) == 38.0);
}


The asm (dmd 2.047 -O -release -inline):

_D6test6b22__T11dot_productVi3TdZ11dot_productFAdAdZd	comdat
		sub	ESP,038h
		mov	EDX,048h[ESP]
		mov	EAX,044h[ESP]
		push	EBX
		mov	ECX,044h[ESP]
		mov	EBX,048h[ESP]
		push	ESI
		dec	EBX
		mov	ESI,044h[ESP]
		mov	8[ESP],EBX
		dec	ESI
		mov	EAX,044h[ESP]
		mov	010h[ESP],ESI
		mov	EAX,8[ESP]
		mov	EBX,010h[ESP]
		dec	EBX
		dec	EAX
		fld	qword ptr [EDX]
		lea	EDX,8[EDX]
		fmul	qword ptr [ECX]
		lea	ECX,8[ECX]
		mov	0Ch[ESP],EDX
		mov	014h[ESP],ECX
		fld	qword ptr [EDX]
		lea	EDX,8[EDX]
		fmul	qword ptr [ECX]
		lea	ECX,8[ECX]
		fld	qword ptr [EDX]
		fmul	qword ptr [ECX]
		faddp	ST(1),ST
		faddp	ST(1),ST
		pop	ESI
		pop	EBX
		add	ESP,038h
		ret	010h

_D6test6b22__T11dot_productVk2TdZ11dot_productFAdAdZd	comdat
		sub	ESP,018h
		mov	EDX,028h[ESP]
		mov	EAX,024h[ESP]
		push	EBX
		mov	ECX,024h[ESP]
		mov	EBX,028h[ESP]
		push	ESI
		mov	ESI,024h[ESP]
		mov	EAX,024h[ESP]
		dec	ESI
		dec	EBX
		fld	qword ptr [EDX]
		lea	EDX,8[EDX]
		fmul	qword ptr [ECX]
		lea	ECX,8[ECX]
		fld	qword ptr [EDX]
		fmul	qword ptr [ECX]
		faddp	ST(1),ST
		pop	ESI
		pop	EBX
		add	ESP,018h
		ret	010h

_D6test6b22__T11dot_productVk1TdZ11dot_productFAdAdZd	comdat
		mov	EDX,010h[ESP]
		mov	EAX,0Ch[ESP]
		mov	EAX,4[ESP]
		fld	qword ptr [EDX]
		mov	EDX,8[ESP]
		fmul	qword ptr [EDX]
		ret	010h

_D6test6b21__T10dotProductTdVk3Z10dotProductFG3dG3dZd	comdat
		sub	ESP,048h
		fld	qword ptr 064h[ESP]
		fmul	qword ptr 04Ch[ESP]
		fldz
		faddp	ST(1),ST
		fstp	qword ptr [ESP]
		fld	qword ptr 06Ch[ESP]
		fld	qword ptr 074h[ESP]
		fxch	ST1
		fmul	qword ptr 054h[ESP]
		fxch	ST1
		fmul	qword ptr 05Ch[ESP]
		faddp	ST(1),ST
		fadd	qword ptr [ESP]
		fstp	qword ptr [ESP]
		fld	qword ptr [ESP]
		add	ESP,048h
		ret	030h


Bye,
bearophile
August 08, 2010
Thanks a lot @bearophile, @Mafi and @Dmitry Olshansky, this is what I was looking for.