Difference between Call-by-name and Call-by-macro-expansion
Asked Answered
S

2

0

Let's assume we have the following code in a language that looks a lot like C.

 int A[2];

 A[0]=4;
 A[1]=7;

    void f(int x, int y) {
     x++; A[1]++; y++;
     printf(x, y, A[0], A[1]);
    }

    void main() {
     int k = 0;
     f(k, A[k]);
     print(k, A[0], A[1]);
    }

I want to define the output of this program. I haven't understood well the difference between the call-by-name and the call-by-macro-expansion method.

So, in the call-by-name method, k is initialized to 0 and then f() function is called. x becomes equal to "k" and y becomes equal to "A[k]". The first command in the called function is x++ which increases the value of "k" by 1. So k becomes equal to 1. Then A[1] is increased, so A[1] becomes 7+1=8. None of the x,y are affected. Finally, we have the command y++ which increases the value of "A[k]" by 1, so it increases the value of A[1] (since now k=1) by 1, so A[1] becomes now 8+1=9.

Then f() prints: 1,9,4,9

And then we return to the main() fuction which prints: 1,4,9

So, the output of the program is 1,9,4,9,1,4,9 if I am not mistaken.

But how does call-by-macro-expansion differs from this method? What does it change?

Scribe answered 22/6, 2019 at 15:49 Comment(10)
What do you mean by "looks a lot like java"? This isn't supposed to be java code? Are you looking for a solution in c/c++ where you have macros? What is the actual programming language you are using? Please edit your question to change the tags to the language you are using. Currently this code doesn't make sense because java does not have "macro expansions".Jasminejason
@Jasminejason Ok I edited my question. I just wanted to understand how this method works in constrast with passing parameters by name. Didn't know Java doesn't support parameter-passing by macro-expansion. So I had just written down a small programm in a hypothetical language (like PseudoCode). Do you know how macro-expansion differs from passing parameters by result?Scribe
Possible duplicate of Call by name vs call by macro expansionJasminejason
@Jasminejason I think that comparing the macro-expansion method with my example on calling by result method will make it more clear to me.Scribe
Your question is very unclear. Both C and Java are strict evaluation languages, where call-by-name is not possible. C has macros but they are primitive (textual substitution only); normally when people talk about "call-by-macro-expansion" they're doing so in the context of a much more powerful macro mechanism. It's unclear exactly what kind of answer you're looking for here, or how well you understand the concept of evaluation strategies in the first place. What do you already understand, and what are you trying to understand?Callant
To start off with, you probably should make sure you understand the difference between call-by-value and call-by-reference first.Callant
@DanielPryden I have understood how passing parameters by value-result works but I haven't understood how passing parameters to a fucntion by macro-expansion works. So, in this case i would like to know what are the differences in the example above (assuming that the language supports both mechanisms)Scribe
Call by name and call by macro expansion are essentially the same thing (a lazy evaluation strategy). The only difference is in how precise the captured "name" is: if it is an expression with free variables, do they get captured or not? Basically call-by-macro-evaluation is "poor man's call-by-name".Callant
@DanielPryden So in my pseudo code what are the differences?Scribe
I think you would need to construct an example in a different language to see a meaningful difference. In this specific case I think the result would be the same, since textual substitution doesn't affect the meaning of any identifiers. Or I guess you could say that macro substitution here would simply be a compile-time error, since k has no meaning inside f.Callant
R
1

But how does call-by-macro-expansion differs from this method? What does it change?

For C, "call-by-macro-expansion" doesn't exist. Instead, for macros the preprocessor does a glorified "cut&paste" operation on raw text.

For example, if you have this:

int A[2];

A[0]=4;
A[1]=7;

#define MACRO(x, y) {         \
    x++; A[1]++; y++;         \
    printf(x, y, A[0], A[1]); \
}

void main() {
    int k = 0;
    MACRO(k, A[k]);
    print(k, A[0], A[1]);
}

Then the preprocessor will cut&paste the text from the macro to where the macro is used and then replace x and y with the arguments you provided, so that (after preprocessing) the source code looks like this:

int A[2];

A[0]=4;
A[1]=7;

void main() {
    int k = 0;
{         \
    k++; A[1]++; A[k]++;         \
    printf(k, A[k], A[0], A[1]); \
}
    print(k, A[0], A[1]);
}

Of course the macros don't need to contain valid code, and the source doesn't even need to be C at all (e.g. you could use the preprocessor to preprocess assembly language source code by telling the compiler "don't compile, just output the preprocessed text"); and there's no real reason why you can't use a completely different preprocessor (with completely different features and/or macro syntax) and feed the resulting text into a C compiler (telling the compiler "don't preprocesses, just compile").

In practice; the main differences for macros and functions are:

  • for macros, there's no type-checking on the parameters, so bugs end up being more annoying to find
  • for macros, a debugger will only say the line number where the macro was expanded and won't say where the code actually came from, so bugs end up being more annoying to find
  • for macros, because they don't have to be valid C you can do some bizarre shenanigans (e.g. #define forever while(1) { so you can use forever i++; } as an infinite loop), and can be powerful for code obfuscation (deliberately making it hard to read the code).
  • for functions, the compiler can decide not to inline the function to reduce code size
  • for functions, you can have recursion (with macros you can't - it'd end up being an infinite amount of text)
  • for functions, you can have function pointers and/or have external functions (where the linker figures out where the function is, either with static linking or dynamic linking).

For a simpler example of (a) difference, consider this code:

#define f(x) { \
    x++;       \
}

void g(int x) {
    x++;
}

void main() {
    int a = 1;
    int b = 1;

    f(a);
    printf("%d\n", a);

    g(b);
    printf("%d\n", b);
}

These look the same, but are not. After expanding the macro and inlining the function, it becomes more like this:

void main() {
    int a = 1;
    int b = 1;

    a++;
    printf("%d\n", a);  // Will print "2' because the original `a` was changed

    int x = b;
    x++;
    printf("%d\n", b);  // Will print "1' because the original `b` was not changed
}

Note that this is exactly the same problem with the example above (for the macro, the x++; modifies the original k and not a copy of the original k; and for the function the x++; modifies a copy and not the original).

Reinhold answered 23/6, 2019 at 13:22 Comment(26)
Thanks for the answer! Could you explain me in which spot will the calculations above change? It will make it more clear through my example.Scribe
@MJ13: Example changed to be a lot closer to your original.Reinhold
macros are not "called" only textually replaced. C does not know anything like call-by-macro.Mosaic
@P__J__: That's exactly what I said in the first sentence??Reinhold
@Reinhold sorry did not notice. Please edit your question to let me ammend my voteMosaic
@Reinhold So can you define the output values on this case?Scribe
@MJ13: For macros, there's no "output value" (like there is for a return something in a function).Reinhold
@Reinhold What I am trying to say is: Which is the output of this program? What will the print commands display?Scribe
@MJ13: It probably won't compile - the printf(k, A[k], A[0], A[1]); should cause a `first argument has the wrong type (not a string)" compile time error.Reinhold
@MJ13: If it did compile, printed values would be 1 9 4 9 and 1 4 9.Reinhold
@Reinhold So, If it did compile somehow then the printed values will be exactly the same with the pass by value-result, right ?Scribe
@MJ13: No - for the original "pass by value" code the output would be 1 9 4 9 and 0 4 9; because whatever happens to k inside the function happens to the copy of the value that was passed and doesn't effect the original value in main().Reinhold
@Reinhold I am sorry...I meant call by name method...Would that be the same with this one? I guess yesScribe
@MJ13: Yes - your "call by name" (a normal function with parameters passed by value) would (if it compiled) print 1 9 4 9 and 0 4 9.Reinhold
@Reinhold I think you are missing something...Check my analysis above and the printed output.Scribe
@MJ13: Your analysis (for "normal function using pass by value") was wrong - main prints 0 4 9 because the value of k never changes The value that is in k gets copied to x and x changes but k does not.Reinhold
@Reinhold I had made a mistake while typing the question...A[1] = 7...Just fixed that. So with this example both call by name and call by macro-expansion methods would give the same result right?Scribe
@Reinhold your makro is still wrong. The macro you wrote has side effects. The function does not.Mosaic
@P__J__: The macro in my example is deliberately "as identical as possible" to the OP's original function so that it's possible to show that the resulting behavior is not equivalent. If the behavior was the same (because there are no side-effect) the example would be pointless.The macro is correct, you are wrong.Reinhold
@MJ13: No, the results will always be different because the function is modifying a copy of k while the macro is modifying the original k. To make the macro behave the same as the function you'd have to create a new variable (e.g. #define MACRO(x, y) int x2 = x; x2++; A[1]++; ...).Reinhold
@Reinhold It's been a long time since I posted this question. But I am trying again now to figure this out. Could you please type the output of your example with macro-expansion ? My code for the call by name method gives an output of 1 9 4 9 1 4 9 . I would like to spot the difference between them in more detail cause I think I get the same results in both cases.Scribe
@MJ13: Added a simpler example to show why the output should be different depending on whether you use a macro or a function. Don't forget that you can compile C code and execute it, and see what it actually does do yourself.Reinhold
@Reinhold I get your point but you are missing my question. You are explaining the difference between the passing by value and the passing by macro . I get that a macro modifies the original value when a call by value doesn't affect it. But my question is : What's the difference between a call by macro and a call by name pass? In both of these 2 cases the original values are affected after a call and not their copies. So in both these examples I think that these 2 methods act the same. I repeat that I am reffering to call by name and not to call by valueScribe
@MJ13: Ok, then... "Call by macro" is factitious nonsense that does not exist (macros are expanded and not called), and "call by name" is factitious nonsense that doesn't really exist either (it's just calling a function by whatever address the compiler assigns to it); and (for C) when calling a function its parameters are always passed by value (and never passed by reference, even when it's the value of a pointer being passed), and for "passed by value" the original value won't/can't be changed by the called function.Reinhold
@Reinhold I just wanted an example where using macro expansion and call by name methods give different output results or just a comparison for the outputs on my example. Something like this: #44491119 . Anyway thanks for your time!Scribe
@MJ13. Ah. For "call by name" (which is better known as "pass by reference"); if C supported it (it doesn't) it'd be like it is in C++ (which supports it); and the main differences will be due to type checking; because macro expansion doesn't know or care about types (in addition to not caring if the text is data and not executable, or even if the text is valid/syntactically correct), but function's parameters do care about types (even when they're passed by reference). In other words; for f(x) as a macro, it'll accept integers, floating point numbers, strings, structures and anything else.Reinhold
M
1

There is nothing like "call-by-macro" in C language. There are only macros which take parameters. Macros are just textually replaced by the preprocessed tokens.

IMO macros should be used only if they are really needed, in most cases it better to use inline functions. Macros are dificult to debus (as compiler compiles the preprocessed .c file) and error prone.

Example

#define SUB(a,b) a-b

and the usage

printf("%d", SUB(3-2,4-5));

the result will not be 2 only -8

Mosaic answered 23/6, 2019 at 13:48 Comment(2)
Could you explain me how the output of my program would change if it was possible to compile?Scribe
If you were to build a hypothetical compiler, you could make it anything you want. You want rainbow colored unicorns? Your compiler could do that.Scorpion

© 2022 - 2024 — McMap. All rights reserved.