I have the following code below (C like language). I know how to trace if pass-by-value or pass-by-reference was used, but there is also call-by-name mechanism. Can anyone guide me how to trace call-by-name?

int x=12,y=10;
void tswap(int pa, int pb) {
   int tmp;
   tmp=pa;
   pa=pb;
   pb=tmp;
   x=x+pa;
   x=x-pb;
   y++;
   printf("%d %d %d %d\n",pa,pb,x,y);
}
int main() {
    int a=4;
    tswap(x,a);
    printf("%d %d %d\n",x,y,a);
    tswap(++x,++y);
    printf("%d %d %d\n",x,y,a);
    return 0;
}

If pass-by-value would be used that output would look like:

4 12 4 11

4 11 4

12 5 12 13

12 13 4

有帮助吗?

解决方案

In general C++ does not use call-by-name. Call-by-name means that the argument to the function is not evaluated on function call. It behaves as if the argument would be substituted into the function body.

Example:

void foo(int a, int b) {
    int s = 0;
    for(int i=0; i<n; i++) {
        s += b;
    }
}

Normally in C++ an example expression like x = foo(3,bar(7)); would behave similar to this:

int tmp = bar(7);
x = foo(3,tmp);

bar is evaluated once and the result given to the function foo.

A language which would use call-by-name would potentially transform foo(3,bar(7)); to

void foo() {
    int s = 0;
    for(int i=0; i<3; i++) {
        s += bar(7);
    }
}

In the first case the function bar would be evaluated once, in the second case it would be evaluated 3 times.


However there are exceptions to that rule. When the function declaration is known (e.g. for templates and inlines) the optimizer may use it to generate optimized code.

Example:

inline unsigned foo(unsigned a, unsigned b) {
    return a / b;
}

If you call a = foo(x,2); the compiler would be smart enough to translate that to a = x/2; and then to a = x >> 1;.

This even goes as far as this example:

inline int foo(int a, int b) {
    if(a == 0) return 0;
    else return b;
}

Now the compiler can indeed transform x = foo(0,bar(17)); to x = 0; thus never calling the function bar. I think this optimization is only done when it is assured that bar has not side-effects.


While C++ does not use call-by-name you can easily use the ideom in C++. Just give a function object/pointer to your function.

Example:

template<typename F>
int foo(int a, F b) {
    int s = 0;
    for(int i=0; i<a; i++) {
        s += b();
    }
}

Now with foo(3, []() { static int i=0; return i++; }), where the second argument is a C++11 lambda, b would be evaluated each time it is encountered in you code.

许可以下: CC-BY-SA归因
不隶属于 StackOverflow
scroll top