Author Topic: var vs out (including "const" related aspects)  (Read 3116 times)

Paolo

  • Hero Member
  • *****
  • Posts: 794
Re: var vs out
« Reply #15 on: August 11, 2026, 06:37:35 pm »
I saw it, thanks.

Mr.Madguy

  • Hero Member
  • *****
  • Posts: 883
Re: var vs out
« Reply #16 on: August 12, 2026, 06:19:07 am »
It's about code optimization. In some cases type conversion should be performed before passing argument to function and then after returning from it. In case of strings for example. In some cases function argument can be reference counted, such as interface for example. "Out" is specified to avoid unnecessary operations.
Is it healthy for project not to have regular stable releases?
Just for fun: Code::Blocks, GCC 13 and DOS - is it possible?

creaothceann

  • Sr. Member
  • ****
  • Posts: 451
Re: var vs out
« Reply #17 on: August 12, 2026, 06:38:45 am »
"out" also avoids warnings about uninitialized variables.

ASerge

  • Hero Member
  • *****
  • Posts: 2518
Re: var vs out
« Reply #18 on: August 12, 2026, 03:50:42 pm »
I don't use OUT much, so I don't remember the exact reasons.
Simple example:
Code: Pascal  [Select][+][-]
  1. {$MODE OBJFPC}
  2. {$APPTYPE CONSOLE}
  3.  
  4. uses Types;
  5.  
  6. procedure SwapPoint(const InR: TPoint; out OutR: TPoint);
  7. begin
  8.   OutR.X := InR.Y;
  9.   OutR.Y := InR.X;
  10. end;
  11.  
  12. var
  13.   R: TPoint = (X: 1; Y: 9);
  14. begin
  15.   SwapPoint(R, R);
  16.   Writeln('X=', R.X, ' Y=', R.Y);
  17.   Readln;
  18. end.
Output "X=9 Y=9".

In debug mode, I always use “Trash Variables” (-gt). In this case, the output looks like this: "X=1431655765 Y=1431655765".

440bx

  • Hero Member
  • *****
  • Posts: 6589
Re: var vs out
« Reply #19 on: August 12, 2026, 04:32:00 pm »
There are several conceptual problems with that "SwapPoint" definition.

The first one is that the parameter InR is being passed by address which openly violates what the documentation states that, in FPC unlike in Delphi, "const" should not be presumed (or cause) a parameter to be passed by reference.

The second is that the call, SwapPoint(R, R) is only valid if the first parameter is passed by value which it should be but isn't and, since it isn't then the "const" contract is violated because because the In parameter is effectively an Out parameter passed by reference.

Very unfortunately and, contrary to what is documented, FPC causes all const parameters larger than a register to be passed by reference _and_ also very unfortunately there is code whose proper functioning depends on that behavior.  One of the most common cases is found in COM definitions where a REFIID, which is a pointer to a GUID, is often specified as a "const GUID<variation>", the only reason that work is because the "const" causes the GUID to be passed by reference.  For the record, that the one case, I cannot forget but, it is not the only case.



FPC v3.2.2 and Lazarus v4.0rc3 on Windows 7 SP1 64bit.

Paolo

  • Hero Member
  • *****
  • Posts: 794
Re: var vs out (including "const" related aspects)
« Reply #20 on: August 12, 2026, 04:47:28 pm »
I have right now updated the topic title to reflect the discussion content.

runewalsh

  • Full Member
  • ***
  • Posts: 131
Re: var vs out (including "const" related aspects)
« Reply #21 on: August 12, 2026, 05:59:42 pm »
out with an unmanaged type simply silences some compiler warnings about uninitalized parameters,
BUT:
out with a managed type forces its re-initialization. For example, out x: ansistring will always automatically assign '' on input, while var x: ansistring keeps its old value. This re-initialization is not free, so use out with managed types only if you don’t care, or if you would re-initialize it anyway.

Zoran

  • Hero Member
  • *****
  • Posts: 1994
    • http://wiki.lazarus.freepascal.org/User:Zoran
Re: var vs out
« Reply #22 on: August 12, 2026, 10:02:46 pm »
Very unfortunately and, contrary to what is documented, FPC causes all const parameters larger than a register to be passed by reference

That is simply not true.

Quote from the documentation:
Quote
Remark Contrary to Delphi, no assumptions should be made about how const parameters are passed to the underlying routine. In particular, the assumption that parameters with large size are passed by reference is not correct. For this the constref parameter type should be used, which is available as of version 2.5.1 of the compiler.

So, the behaviour you describe is obviously according to documentation.

_and_ also very unfortunately there is code whose proper functioning depends on that behavior.

Such code is written against documented behaviour, so there is no "proper" functioning of it.

If the functioning of a routine depends on how a parameter is passed, and that parameter has const modifier, it's the error of sloppy programmer who didn't follow the clearly documented warning.
Swan, ZX Spectrum emulator https://github.com/zoran-vucenovic/swan

440bx

  • Hero Member
  • *****
  • Posts: 6589
Re: var vs out (including "const" related aspects)
« Reply #23 on: August 13, 2026, 12:56:32 am »
I'm afraid the bottom line is as follows: FPC does NOT behave according to the documentation and there is FPC code that depends on what is documented not being true.

FPC v3.2.2 and Lazarus v4.0rc3 on Windows 7 SP1 64bit.

kupferstecher

  • Hero Member
  • *****
  • Posts: 629
Re: var vs out (including "const" related aspects)
« Reply #24 on: August 13, 2026, 12:49:22 pm »
out with a managed type forces its re-initialization.
That I had to learn the hard way, the re-initialisation means the existing value is discarded, even if the variable is not touched inside the procedure. Sure it was used wrong, var would be correct, but that kind of error is not intuitive and not very easy to spot. So I think it should just work like a var parameter but with different warnings. And not doing some minor code optimisations (that in the end leads to mistakes).

PascalDragon

  • Hero Member
  • *****
  • Posts: 6430
  • Compiler Developer
Re: var vs out
« Reply #25 on: August 14, 2026, 08:24:17 pm »
knowing in which way the parameters are passed it is an important aspect !
statement like "..no assumption.." calls for avoiding using const key word at all.

In 99.99% of cases it doesn't matter whether a constant parameter is passed by reference or not. In general const is better regarding optimization than constref. For example assume the following:

Code: Pascal  [Select][+][-]
  1. procedure SomeProc(constref aBuf: LongInt);
  2. { ... }
  3. SomeProc(42);

In this case the compiler will allocate a temporary variable for which it can pass the reference, while with const it will use a register if the calling convention permits.

Dankan1890, that is a trick how you can pass an array into function. It useful when you have many overloads like:
Code: Pascal  [Select][+][-]
  1. function Func(constref Arr: Byte; Count: SizeUInt): Integer;
  2. function Func(constref Arr: ShortInt; Count: SizeUInt): Integer;
  3. function Func(constref Arr: Word; Count: SizeUInt): Integer;
  4. function Func(constref Arr: SmallInt; Count: SizeUInt): Integer;
  5. {...}
This is useful because then you can write:
Code: Pascal  [Select][+][-]
  1. Func(Arr[0], 42);
and depending of type of Arr the correct function will be called. You may even change the type of Arr and the code will keep doing the correct operation (of course you need to implement all needed overloads).

You should not abuse constref for thing like this. Best use an open array parameter which allows you to pass both arrays (dynamic and static) and single elements and you don't even need to pass the count separately.

Very unfortunately and, contrary to what is documented, FPC causes all const parameters larger than a register to be passed by reference _and_ also very unfortunately there is code whose proper functioning depends on that behavior.  One of the most common cases is found in COM definitions where a REFIID, which is a pointer to a GUID, is often specified as a "const GUID<variation>", the only reason that work is because the "const" causes the GUID to be passed by reference.  For the record, that the one case, I cannot forget but, it is not the only case.

Considering that const is not defined for the calling conventions it's up to FPC how to pass such parameters.

440bx

  • Hero Member
  • *****
  • Posts: 6589
Re: var vs out
« Reply #26 on: August 14, 2026, 09:25:21 pm »
Considering that const is not defined for the calling conventions it's up to FPC how to pass such parameters.
Be that as it may, its use when applied to REFIID violates what the documentation states because the definition's correctness is dependent on FPC passing by reference which, as already stated, violates what the documentation states.

Effectively, when a const parameter does not fit in a register, FPC always passes it by reference and, there is code that depends on that.


FPC v3.2.2 and Lazarus v4.0rc3 on Windows 7 SP1 64bit.

ASerge

  • Hero Member
  • *****
  • Posts: 2518
Re: var vs out
« Reply #27 on: August 15, 2026, 08:15:41 am »
Effectively, when a const parameter does not fit in a register, FPC always passes it by reference and, there is code that depends on that.
Records, even if they fit into the register, are passed by reference.

440bx

  • Hero Member
  • *****
  • Posts: 6589
Re: var vs out
« Reply #28 on: August 15, 2026, 08:42:28 am »
Records, even if they fit into the register, are passed by reference.
That has nothing to do with the fact that a const parameter that does not fit in a register is, contrary to what the documentation states, always passed by reference and that there is code that depends on that behavior, among them REFIID parameters.
FPC v3.2.2 and Lazarus v4.0rc3 on Windows 7 SP1 64bit.

ASerge

  • Hero Member
  • *****
  • Posts: 2518
Re: var vs out
« Reply #29 on: August 23, 2026, 08:16:49 am »
That has nothing to do with the fact that...
This was just an addition. “does not fit” not a mandatory condition, but it sufficient.

 

TinyPortal © 2005-2018