Passing functions to functionals

Dmitry Olshansky dmitry.olsh at gmail.com
Tue Nov 30 07:49:56 PST 2010


On 30.11.2010 14:59, Lars T. Kyllingstad wrote:
> In my library I have a lot of functionals (functions that take other
> functions as parameters).  Here is an example that shows the style I use
> to define them:
>
>      // Example: Evaluate the function/delegate/functor f at x.
>      auto eval(F, X)(F f, X x) { return f(x); }
>
>      // Test
>      void main()
>      {
>          int add2(int i) { return i + 2; }
>          assert (eval(&add2, 1) == 3);
>      }
>
> In other words, the function is passed as a run-time parameter.  I've
> seen this (or similar) style used in Phobos, but there, I've also noted
> that functions are sometimes passed as template alias parameters:
>
>      // Same as above, using template alias parameter.
>      auto eval(alias f, X)(X x) { return f(x); }
>
>      // Test
>      void main()
>      {
>          int add2(int i) { return i + 2; }
>          assert (eval!add2(1) == 3);
>      }
>
> I'd be grateful if people would share their knowledge of the pros and
> cons of each method.  For instance, are there any situations where
> template alias parameters don't work?
>
>
> Thanks,
>
> -Lars
alias parameters must be know/computable at compile time, quick example 
on what you can't do:

import std.stdio;

auto eval(F, X)(F f, X x) { return f(x); }
auto eval2(alias f,X)(X x){ return f(x); }

auto summator(int k){
     int f(int val){
         return k + val;
     }
     return &f;
}


  // Test
void main()
{
      int add2(int i) { return i + 2; }
     int traceAdd2(int i){
         writeln(i," --> ",i+2);
         return i+2;
     }
     int delegate(int) getAdd2(){
         writeln("Getting add2");
         return &add2;
     }
      assert(eval(&add2, 1) == 3);
      assert(eval2!add2(1) == 3);
     assert(eval(summator(2),1) == 3);
     //Next one fails with
     //Error: closures are not yet supported in CTFE
     //Error: cannot evaluate summator(2) at compile time
     //assert(eval2!(summator(2))(1) == 3);

     assert(eval(&traceAdd2,1) == 3);
     assert(eval2!traceAdd2(1) == 3); //side effect in call is no problem

     assert(eval(getAdd2,1) == 3);
     //Next one fails with
     //Error: cannot evaluate writeln("Getting add2") at compile time
     //Error: cannot evaluate getAdd2() at compile time
     //assert(eval2!(getAdd2())(1) == 3);
}

Well, once the limitations of CTFE are dealt with, the only problem 
alias param not capable of would be user input parameters, and 
side-effects during delegate/function construction.
IMHO this can pose a problem with some algorithms in std.algorithm, like 
_filter_ing on user provided criteria currently impossible (since 
predicate parameter to filter has to be known at compile time). One 
soultion might be is somehow provide alternative versions of the with 
the first version of syntax.

A distinctive feature of alias parameters - they are not passed as 
arguments at all, as the (stripped) asm suggests:
for eval2!add2(1):
_TEXT:00405AB4                 enter   4, 0
_TEXT:00405AB8                 mov     [ebp+var_4], eax
_TEXT:00405ABB                 push    [ebp+arg_0]
_TEXT:00405ABE                 mov     eax, [ebp+var_4]
_TEXT:00405AC1                 call    test_e at main@add2; direct call, 
compiler knows what the alias is
_TEXT:00405AC6                 leave
_TEXT:00405AC7                 retn    4

eval(&add2, 1):
_TEXT:00405A98 var_4           = dword ptr -4
_TEXT:00405A98 arg_0           = dword ptr  8
_TEXT:00405A98 arg_4           = dword ptr  0Ch
_TEXT:00405A98
_TEXT:00405A98                 enter   4, 0
_TEXT:00405A9C                 push    ebx
_TEXT:00405A9D                 mov     [ebp+var_4], eax
_TEXT:00405AA0                 push    [ebp+var_4]
_TEXT:00405AA3                 mov     eax, [ebp+arg_0]
_TEXT:00405AA6                 mov     edx, [ebp+arg_4]
_TEXT:00405AA9                 mov     ebx, [ebp+arg_0]
_TEXT:00405AAC                 call    edx ;<---- note the indirect call
_TEXT:00405AAE                 pop     ebx
_TEXT:00405AAF                 leave
_TEXT:00405AB0                 retn    8

That's as far as I can get for now, there is still room for investigation.
-- 

Dmitry Olshansky



More information about the Digitalmars-d-learn mailing list