More info: https://forum.nim-lang.org/t/4010
This is a serious issue...
How I fixed it for me: https://github.com/ConsoleTVs/TFG/commit/c3698f64a08adf4dc5bb19579e56ff180009ba1a#diff-ecd2a08316dc75e0142a9547a218c408
EDIT: added code to repreduce:
var current: int = 0
proc gen(): string = current.inc; $(current - 1)
proc allOut(a, b, c: string) =
echo a
echo b
echo c
allOut(gen(), gen(), gen())
Please, can you add details here on how to reproduce the issue?
The issue itself seems to evaluate the arguments of functions in a different order when using c++ backend.
In my case. As the fixed link i gave, you can see how to fix it by forcing to evaluate the parameters outside the argument list. Somebosy answered that on the forum, it might help you out
Yeah, that is clear, I was asking if you could post a reproducible example here that does not involve external resources and repositories
Yes sure:
var current: int = 0
proc gen(): string = current.inc; $(current - 1)
proc allOut(a, b, c: string) =
echo a
echo b
echo c
allOut(gen(), gen(), gen())
This will give:
c:
1
2
cpp:
1
0
Thank you!
I can confirm that indeed the C++ generated output is indeed as above, whereas C produces the expected output.
Nice catch @ConsoleTVs :+1:
@stefanos82 hehe, It was discovered while developing a stack based VM, where the order of POP instructions matter :3 Still kinda fixable by using a variable asign and then pass the arguments. The problem relies in evaluation order of arguments :)
Thanks tho!
I wonder if one could make a forceOrderOfEvaluation macro that automatically does the rewrite using temporaries for all function calls in its body
@andreaferretti That's entirely possible, but it's just a C++ codegen bug and shouldn't be hard to fix either.
Well I looked at the generated cpp code and the generated c code:
c:
T1_ = (NimStringDesc*)0;
T1_ = gen_kR9bLIeU6XIHDD3f3654Jsg();
T2_ = (NimStringDesc*)0;
T2_ = gen_kR9bLIeU6XIHDD3f3654Jsg();
T3_ = (NimStringDesc*)0;
T3_ = gen_kR9bLIeU6XIHDD3f3654Jsg();
allOut_b3bLY9bg2hfU2vLNvWPXntw(T1_, T2_, T3_);
cpp
allOut_b3bLY9bg2hfU2vLNvWPXntw(gen_kR9bLIeU6XIHDD3f3654Jsg(), gen_kR9bLIeU6XIHDD3f3654Jsg(), gen_kR9bLIeU6XIHDD3f3654Jsg());
My personal opinion is that it is weird that they differ this much. But apart from that I think both are correct. I think no program should rely on the order of argument evaluation. Is the order of argument evaluation specified in Nim? Because in neither C nor Cpp it is specified. On a different C++ compiler you might get a different order of argument evaluation. I know this and I never had problems with this.
Is the order of argument evaluation specified in Nim? Because in neither C nor Cpp it is specified.
It is not yet written down, but the order of evaluation is left-to-right and the C++ code needs to introduce temporaries just like the C version does.
@krux02 @Araq
I agree with @Araq , The order is left to right. Yet even if diferent programing languages like c / cpp / js differ in argument evaluation or other things, the nim compiler should ALWAYS make sure the entire program does exactly the same regardless of the backend.
@ConsoleTVs As I said it is not just that different programming languages differ in argument evaluation, it is that different compilers differ in argument evaluation order. Try it with different backend like visual studio compiler and gcc. So I wouldn't argument that this issue is [IMPORTANT]. It wouldn't be a surprise to any programmer who comes from c or c++ that you should not rely on the order of argument evaluation. Not just because compilers might change the order at will, but also because of readability.