Call by name vs call by macro expansion
Asked Answered
H

1

10

In non strict evaluation languages, what are the differences and advantages/disadvantages of using call by name vs call by macro expansion?

Could you provide an example that explains both evaluation strategies?

Thanks!

Herson answered 12/6, 2017 at 2:30 Comment(0)
D
6

Call By Name:

Call by name is an evaluation strategy where the arguments to a function are not evaluated before the function is called—rather, they are substituted directly into the function body (using capture-avoiding substitution) and then left to be evaluated whenever they appear in the function. If an argument is not used in the function body, the argument is never evaluated; if it is used several times, it is re-evaluated each time it appears. (See Jensen's Device.)

Call-by-name evaluation is occasionally preferable to call-by-value evaluation. If a function's argument is not used in the function, call by name will save time by not evaluating the argument, whereas call by value will evaluate it regardless. If the argument is a non-terminating computation, the advantage is enormous. However, when the function argument is used, call by name is often slower, requiring a mechanism such as a thunk.

An early use was ALGOL 60. Today's .NET languages can simulate call by name using delegates or Expression parameters. The latter results in an abstract syntax tree being given to the function. Eiffel provides agents, which represent an operation to be evaluated when needed. Seed7 provides call by name with function parameters.

Call By Macro :

Call by macro expansion is similar to call by name, but uses textual substitution rather than capture-avoiding substitution. With uncautious use, macro substitution may result in variable capture and lead to undesired behavior. Hygienic macros avoid this problem by checking for and replacing shadowed variables that are not parameters.

NOTE: In non strict evaluation languages

Example Call By Macro :

Call by Macro Expansion: many programming languages, including C, lisp and scheme, provide developers with a mechanism to add new syntax to the core language grammar called macros. Macros are expanded into code by a macro preprocessor. These macros might contain arguments, which are copied in the final code that the preprocessor produces. As an example, the C program below implements the swap function via a macro:

#define SWAP(X,Y) {int temp=X; X=Y; Y=temp;} int main() {   int a = 2;   int b = 3;   printf("%d, %d\n", a, b);   SWAP(a, b);   printf("%d,
> %d\n", a, b); } 

This macro implements a valid swap routine. The

preprocessed program will look like the code below. Because the body of the macro is directly copied into the text of the calling program, it operates on the context of that program. In other words, the macro will refer directly to the variable names that it receives, and not to their values.

int main() {   int a = 2;   int b = 3;   printf("%d, %d\n", a, b);   {
> int tmp = (a); (a) = (b); (b) = tmp; };   printf("%d, %d\n", a, b); }

The expressions passed to the macro as parameters are evaluated every time they are used in the body of the macro. If the argument is never used, then it is simply not evaluated. As an example, the program below will increment the variable b twice:

#define MAX(X, Y) ((X) > (Y) ? (X) : (Y)) int main() { int a = 2, b = 3; int c = MAX(a, b++); printf("a = %d, b = %d, c = %d\n", a, b, c); } Macros suffer from one problem, called variable capture. If a macro defines a variable v that is already defined in the environment of the caller, and v is passed to the macro as a parameter, the body of the macro will not be able to distinguish one occurrence of v from the other. For instance, the program below has a macro that defines a variable temp. The call inside main causes the variable temp defined inside this function to be captured by the definition inside the macro's body.

#define SWAP(X,Y) {int temp=X; X=Y; Y=temp;} int main() {   int a = 2;   int temp = 17;   printf("%d, temp = %d\n", a, temp);   SWAP(a, temp); 
> printf("%d, temp = %d\n", a, temp); }

Once this program is expanded by

the C preprocessor, we get the code below. This program fails to exchange the values of variables temp and a:

int main() {   int a = 2;   int temp = 17;   printf("%d, temp = %d\n",
> a, temp);   {int temp=a; a=temp; temp=temp;};   printf("%d, temp =
> %d\n", a, temp); }

There are a number of lazy evaluation strategies

that avoid the variable capture problem. The two best known techniques are call-by-name and call-by-need.

Example Call By Name :

Call by Name: in this evaluation strategy the actual parameter is only evaluated if used inside the function; however, this evaluation uses the context of the caller routine. For instance, in the example below, taken from Weber's book, we have a function g that returns the integer 6. Inside the function f, the first assignment, e.g., b = 5, stores 5 in variable i. The second assignment, b = a, reads the value of i, currently 5, and adds 1 to it. This value is then stored at i.

void f(by-name int a, by-name int b) {
  b=5;
  b=a;
}
int g() {
  int i = 3;
  f(i+1,i);
  return i;
}

Very few languages implement the call by name evaluation strategy. The most eminent among these languages is Algol. Simula, a direct descendent of Algol, also implements call by name, as we can see in this example. The call by name always causes the evaluation of the parameter, even if this parameter is used multiple times. This behavior might be wasteful in referentially transparent languages, because, in these languages variables are immutable.

Derain answered 10/8, 2017 at 4:55 Comment(1)
@Derain Could you pls check my similar post: #56717384 . I am trying to find out if call by macro expansion and call by name methods give different output results on my example. If not , I would like to see an example where call by name differs from call by macro expansion.Sidell

© 2022 - 2024 — McMap. All rights reserved.