Lazarus

Free Pascal => General => Topic started by: clerfayt on April 17, 2021, 10:05:57 am

Title: Order of parameter evaluation
Post by: clerfayt on April 17, 2021, 10:05:57 am
Hej,
I searched the forums and FPC documentation but did not find an answer to my question:
Is the order of parameter evaluation always the same? If so, can someone provide a link to where this is documented?

I am wondering because I have a function taking a variable parameter which gets changed, so the order of calling this function matters. Take the following simple example program:

Code: Pascal  [Select][+][-]
  1. program evalordertest;
  2.  
  3. {$mode objfpc}{$H+}
  4.  
  5. uses sysutils;
  6.  
  7. function inc(var v: Integer; const i: Integer): Integer;
  8. { increment the var v and return it. }
  9. begin
  10.   write('(' + IntToStr(v) + '+' + IntToStr(i) + ') ');
  11.   v := v + i;
  12.   Result := v;
  13. end;
  14.  
  15. function mean(const a,b: Integer): Single;
  16. begin
  17.   Result := (a+b)/2;
  18. end;
  19.  
  20. var
  21.   x: Integer = 0;
  22.   y: Integer = 0;
  23. begin
  24.   writeln('=> ' + FormatFloat('0', mean( inc(x,20), inc(x,100) ) ));
  25.   writeln('=> ' + FormatFloat('0', mean( inc(y,100), inc(y,20) ) ));
  26. end.

This outputs:
Code: Text  [Select][+][-]
  1. (0+100) (100+20) => 110
  2. (0+20) (20+100) => 70

Calling the function inc twice within another function call (mean) obviously leads to different results, depending on the order of parameter evaluation.

In this case, it seems that the second parameter gets evaluated first.
(I used the FPC 3.0.4 on Linux x86-64)
But may I rely on this behaviour? Or does it depend on compiler optimizations an/or settings? And what about different compiler versions?

Thanks in advance!
Title: Re: Order of parameter evaluation
Post by: PascalDragon on April 17, 2021, 10:50:47 am
In this case, it seems that the second parameter gets evaluated first.
(I used the FPC 3.0.4 on Linux x86-64)
But may I rely on this behaviour? Or does it depend on compiler optimizations an/or settings? And what about different compiler versions?

No, you can't. The order of evulation is not guaranteed by FPC as this way it may apply better optimizations. It's semi-documented here (https://wiki.freepascal.org/Code_Conversion_Guide#Order_of_parameter_evaluation) (and probably should be added to the official documentation).
Title: Re: Order of parameter evaluation
Post by: clerfayt on April 17, 2021, 11:42:01 am
thx for the quick reply.
well then..
I guess, it's bad code design anyway, to depend on the order of parameter evaluation :)
Title: Re: Order of parameter evaluation
Post by: Josh on April 17, 2021, 11:57:24 am
not tested but maybe make it inlined?

Code: Pascal  [Select][+][-]
  1. function inc( Var v: Integer; const i: Integer): Integer; inline;

Title: Re: Order of parameter evaluation
Post by: lucamar on April 17, 2021, 12:50:41 pm
not tested but maybe make it inlined?

Inlining doesn't guarantee when each parameter will be evaluated, so the "problem" persist: the inlined code for the second parameter might be either before or after that of the first, depending on target, optimization level, phase of the moon, ...
Title: Re: Order of parameter evaluation
Post by: Zoran on April 17, 2021, 01:12:37 pm
It's semi-documented here (https://wiki.freepascal.org/Code_Conversion_Guide#Order_of_parameter_evaluation) (and probably should be added to the official documentation).

It is officially documented quite well, as a remark in chapter Expressions: https://www.freepascal.org/docs-html/current/ref/refch12.html (https://www.freepascal.org/docs-html/current/ref/refch12.html)

EDIT:
Actually no, we are talking about function parameters, and not the order of expressions, sorry.
Title: Re: Order of parameter evaluation
Post by: MarkMLl on April 17, 2021, 01:31:37 pm
Inlining doesn't guarantee when each parameter will be evaluated, so the "problem" persist: the inlined code for the second parameter might be either before or after that of the first, depending on target, optimization level, phase of the moon, ...

OP should also note that PascalDragon didn't say "implementation defined", i.e. might depend on the target and the precise version of the compiler, he specifically said "may apply better optimizations" so there's no guarantee that consecutive invocations of the same function will have the same parameter evaluation order. And I suspect that inlining, by potentially allowing the optimiser to look at a bigger tree, could make that "worse" rather than "better".

Hypothetically at least:

Code: Pascal  [Select][+][-]
  1. function foo(const a, b: integer): integer; // function definition, body not shown
  2.  
  3. ...
  4. begin // Main part of program
  5.   z := foo(x, bar(y));
  6.   t := foo(bar(y), 42)
  7. end.
  8.  

The value of bar(y) can't have changed, so there's no absolute guarantee of the order or even number of times that the parameters are evaluated.

MarkMLl
Title: Re: Order of parameter evaluation
Post by: nanobit on April 17, 2021, 05:51:37 pm
To enlarge the picture, the call-order position of a getRef-function (instance expression)
can be different too ( tested on Windows with FPC3.2 and all Delphi Versions):

getRef.doSomething( getArg1);   
// FPC: getRef, getArg1, doSomething()
// Delphi: getArg1, getRef, doSomething()

getRef.prop := getRef2.do2;   
// FPC: getRef, getRef2, do2, setProp()
// Delphi: getRef2, do2, getRef, setProp()
Title: Re: Order of parameter evaluation
Post by: PascalDragon on April 18, 2021, 01:29:45 pm
Inlining doesn't guarantee when each parameter will be evaluated, so the "problem" persist: the inlined code for the second parameter might be either before or after that of the first, depending on target, optimization level, phase of the moon, ...

OP should also note that PascalDragon didn't say "implementation defined", i.e. might depend on the target and the precise version of the compiler, he specifically said "may apply better optimizations" so there's no guarantee that consecutive invocations of the same function will have the same parameter evaluation order. And I suspect that inlining, by potentially allowing the optimiser to look at a bigger tree, could make that "worse" rather than "better".

Correct. In theory the absolute same invocations right after each other could have different evaluation order of their parameters.
Title: Re: Order of parameter evaluation
Post by: jamie on April 18, 2021, 03:20:23 pm
I have run into this already using fpc. in 32 bit target I can use the PASCAL call convention and it seems to always call the arguments in the order that I present them... AS it should be

 So this means you can serialize the parameters from a stream of what ever using a single function..

 I moved a project from Delphi over to fpc and found this to no longer to be true. in 32 bit target using fpc I can specify the PASCAL call and it seems to work . With 64 bit target that is no longer an option, the PASCAL call no longer exists and parameter order can no longer be dependent on..

 In short, I ended up filling a local array so that I can parse it in order but all that did was decrease the performance of the code.

 That project upended with a performance taking a hit.

 if you are targeting 32 bit you may want to experiment with the PASCAL call convention, that is, if they haven't taken that out already, too.

Title: Re: Order of parameter evaluation
Post by: Thaddy on April 18, 2021, 03:45:00 pm
Jamie: Platform please. (I assume you mean Windows)
Title: Re: Order of parameter evaluation
Post by: PascalDragon on April 19, 2021, 09:14:02 am
I have run into this already using fpc. in 32 bit target I can use the PASCAL call convention and it seems to always call the arguments in the order that I present them... AS it should be

The order in which parameters are passed and in which they're evaluated are two different things. The former is fixed through the ABI, but the later is not. And if the compiler should see an opportunity to generate better code it will change the evaluation order. Only because you don't see it in your code doesn't mean that the compiler never does so.
Title: Re: Order of parameter evaluation
Post by: glorfin on April 19, 2021, 12:35:05 pm
Quote
Calling the function inc twice within another function call (mean) obviously leads to different results, depending on the order of parameter evaluation.
I understand that this is exactly why Inc and Dec are procedures in Pascal. Ambiguity caused by these functions in other languages is notorious.
TinyPortal © 2005-2018