Thread overview
Templates, varargs and static foreach
Jan 14, 2007
%u
Jan 14, 2007
Kirk McDonald
Jan 14, 2007
%u
Jan 14, 2007
%u
January 14, 2007
I would like to do the following:

void foo() {}
void bar(int a) { foo(); } // 1
void bar(int a, int b) { foo(); foo(); } // 2
void bar(int a, int b, int c) { foo(); foo(); foo(); } // 3
void bar(int[] a) { foreach(b; a) foo(); } // 4

The forms 1-3 should be called, when the amount of arguments is known at compile time. Otherwise 4 is called.

Ok - this is a major simplification of the design I'm using. I would like to shorten it using templates. I have tried this:

void foo() {}
void bar(A...)(A a) { foo(); static if (a.length > 1) { bar(a[1..length]); }
void bar(A)(A[] a) { foreach(t;a) foo(); }

The problem is that the recursion happens on runtime (unless I specify -O -release -inline). Can the compiler guarantee that the recursion is unfolded, when all those optimizations are on or is there a static for/foreach for doing this in a better way.
January 14, 2007
%u wrote:
> I would like to do the following:
> 
> void foo() {}
> void bar(int a) { foo(); } // 1
> void bar(int a, int b) { foo(); foo(); } // 2
> void bar(int a, int b, int c) { foo(); foo(); foo(); } // 3
> void bar(int[] a) { foreach(b; a) foo(); } // 4
> 
> The forms 1-3 should be called, when the amount of arguments is known at compile time. Otherwise
> 4 is called.
> 
> Ok - this is a major simplification of the design I'm using. I would like to shorten it using
> templates. I have tried this:
> 
> void foo() {}
> void bar(A...)(A a) { foo(); static if (a.length > 1) { bar(a[1..length]); }
> void bar(A)(A[] a) { foreach(t;a) foo(); }
> 
> The problem is that the recursion happens on runtime (unless I specify -O -release -inline). Can
> the compiler guarantee that the recursion is unfolded, when all those optimizations are on or is
> there a static for/foreach for doing this in a better way.

There is a "static foreach," only you do not use the "static" keyword.

void foo() {}

void bar(A...)(A a) {
    foreach(e; a) {
        foo();
    }
}

You could also do this at runtime, using D's typesafe variadics:

void bar(int[] a...) {
    foreach(e; a) {
        foo();
    }
}

Both forms of bar are called in exactly the same way, with the caveat that the latter only accepts int arguments, while the former will accept any arguments.

bar(1, 2, 3, 4);

-- 
Kirk McDonald
Pyd: Wrapping Python with D
http://pyd.dsource.org
January 14, 2007
>There is a "static foreach," only you do not use
>the "static" keyword.

> void foo() {}
>
> void bar(A...)(A a) {
>      foreach(e; a) {
>          foo();
>      }
> }

Dear Kirk, I tried this too, but disassembling to code reveals that the foreach generates extra instructions when compared to this (dmd 1.00 linux):

 void bar(A...)(A a) {
      static if (a.length>0) foo();
      static if (a.length>1) foo();
      static if (a.length>2) foo();
      static if (a.length>3) foo();
      ...
 }

I tried this without any optimizations. I just want to be sure that the compiler guarantees the behaviour at compile time. This function is time critical.
January 14, 2007
> Dear Kirk, I tried this too, but disassembling to code reveals that the foreach generates extra instructions when compared to this (dmd 1.00 linux):

The optimizer eliminates the extra code - not a problem anymore. I just wondered, why doesn't it do it all on compile time. Here's the dumbobj output:

static if's:
   0:   55                      push   %ebp
   1:   8b ec                   mov    %esp,%ebp
   3:   e8 fc ff ff ff          call   4 <_D2t216__T3abcTiTiTiTiZ3abcFiiiiZv+0x4>
   8:   e8 fc ff ff ff          call   9 <_D2t216__T3abcTiTiTiTiZ3abcFiiiiZv+0x9>
   d:   e8 fc ff ff ff          call   e <_D2t216__T3abcTiTiTiTiZ3abcFiiiiZv+0xe>
  12:   e8 fc ff ff ff          call   13 <_D2t216__T3abcTiTiTiTiZ3abcFiiiiZv+0x13>
  17:   5d                      pop    %ebp
  18:   c2 0c 00                ret    $0xc
  1b:   90                      nop

foreach:
   0:   55                      push   %ebp
   1:   8b ec                   mov    %esp,%ebp
   3:   83 ec 04                sub    $0x4,%esp
   6:   53                      push   %ebx
   7:   89 45 fc                mov    %eax,0xfffffffc(%ebp)
   a:   8b 4d 10                mov    0x10(%ebp),%ecx
   d:   e8 fc ff ff ff          call   e <_D2t216__T3bcdTiTiTiTiZ3bcdFiiiiZv+0xe>
  12:   8b 45 0c                mov    0xc(%ebp),%eax
  15:   e8 fc ff ff ff          call   16 <_D2t216__T3bcdTiTiTiTiZ3bcdFiiiiZv+0x16>
  1a:   8b 55 08                mov    0x8(%ebp),%edx
  1d:   e8 fc ff ff ff          call   1e <_D2t216__T3bcdTiTiTiTiZ3bcdFiiiiZv+0x1e>
  22:   8b 5d fc                mov    0xfffffffc(%ebp),%ebx
  25:   e8 fc ff ff ff          call   26 <_D2t216__T3bcdTiTiTiTiZ3bcdFiiiiZv+0x26>
  2a:   5b                      pop    %ebx
  2b:   c9                      leave
  2c:   c2 0c 00                ret    $0xc
  2f:   90                      nop