Recent

Author Topic: Order of parameter evaluation  (Read 806 times)

clerfayt

  • New member
  • *
  • Posts: 5
Order of parameter evaluation
« 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!

PascalDragon

  • Hero Member
  • *****
  • Posts: 2981
  • Compiler Developer
Re: Order of parameter evaluation
« Reply #1 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 (and probably should be added to the official documentation).

clerfayt

  • New member
  • *
  • Posts: 5
Re: Order of parameter evaluation
« Reply #2 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 :)

josh

  • Hero Member
  • *****
  • Posts: 827
Re: Order of parameter evaluation
« Reply #3 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;

« Last Edit: April 17, 2021, 12:05:08 pm by josh »
Development Installation Lazarus 1.3, FPC 2.7.1,Windows 7/8 32/64, OSX, *nix

Test Environment Lazarus & FPC Trunk on Windows and OSX (Cocoa Mainly on OSX). Testing also Crosscompile windows to OSX.. 
Any posts made from 2015 will be based on Lazarus Trunk.

lucamar

  • Hero Member
  • *****
  • Posts: 3891
Re: Order of parameter evaluation
« Reply #4 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, ...
Turbo Pascal 3 CP/M - Amstrad PCW 8256 (512 KB !!!) :P
Lazarus/FPC 2.0.8/3.0.4 & 2.0.12/3.2.0 - 32/64 bits on:
(K|L|X)Ubuntu 12..18, Windows XP, 7, 10 and various DOSes.

Zoran

  • Hero Member
  • *****
  • Posts: 1667
    • http://wiki.lazarus.freepascal.org/User:Zoran
Re: Order of parameter evaluation
« Reply #5 on: April 17, 2021, 01:12:37 pm »
It's semi-documented here (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

EDIT:
Actually no, we are talking about function parameters, and not the order of expressions, sorry.
« Last Edit: April 17, 2021, 01:16:45 pm by Zoran »

MarkMLl

  • Hero Member
  • *****
  • Posts: 2543
Re: Order of parameter evaluation
« Reply #6 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
Turbo Pascal v1 on CCP/M-86, multitasking with LAN and graphics in 128Kb.
Pet hate: people who boast about the size and sophistication of their computer.
GitHub repositories: https://github.com/MarkMLl?tab=repositories

nanobit

  • Full Member
  • ***
  • Posts: 107
Re: Order of parameter evaluation
« Reply #7 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()

PascalDragon

  • Hero Member
  • *****
  • Posts: 2981
  • Compiler Developer
Re: Order of parameter evaluation
« Reply #8 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.

jamie

  • Hero Member
  • *****
  • Posts: 4454
Re: Order of parameter evaluation
« Reply #9 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.

The only true wisdom is knowing you know nothing

Thaddy

  • Hero Member
  • *****
  • Posts: 10786
Re: Order of parameter evaluation
« Reply #10 on: April 18, 2021, 03:45:00 pm »
Jamie: Platform please. (I assume you mean Windows)

PascalDragon

  • Hero Member
  • *****
  • Posts: 2981
  • Compiler Developer
Re: Order of parameter evaluation
« Reply #11 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.

glorfin

  • Full Member
  • ***
  • Posts: 130
  • LMath supporter
Re: Order of parameter evaluation
« Reply #12 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