Recent

Author Topic: [Solved] Is it possible to const an argument passed by reference in FPC?  (Read 16493 times)

ikel

  • New Member
  • *
  • Posts: 26
Hi,

In C++ we can const an argument passed by reference,

Code: Pascal  [Select][+][-]
  1. bool isValidEntry(const std::string &input)

Is it possible to do this in FPC?

Thanks.
« Last Edit: August 07, 2019, 05:08:56 am by ikel »

440bx

  • Hero Member
  • *****
  • Posts: 4014
Re: Is it possible to const an argument passed by reference in FPC?
« Reply #1 on: July 24, 2019, 03:45:56 am »
Yes, in FPC instead of "const" you specify "constref".
(FPC v3.0.4 and Lazarus 1.8.2) or (FPC v3.2.2 and Lazarus v3.2) on Windows 7 SP1 64bit.

marcov

  • Administrator
  • Hero Member
  • *
  • Posts: 11444
  • FPC developer.
Re: Is it possible to const an argument passed by reference in FPC?
« Reply #2 on: July 24, 2019, 10:38:47 am »
By reference parameters in Pascal don't base on pointer syntax like in C (& or *) .  You therefore don't need to micro manage it, but use proper by ref language constructs like const/var/out.

constref only makes a const argument forcedly by ref, but this is rarely used because strings and dynamic arrays already contain an implicit ref. So the most direct translation would be

Code: [Select]
function isValidEntry(const input: string):boolean;

Besides this there is also the formal and open array parameter which also implies ref, and can be used for e.g. static arrays.

procedure x(const y);   // untyped (const void pointer)
procedure x(const y:array of z);

So a syntax where you can assign the pointer of a by ref argument doesn't exist with const or var. The whole problem simply doesn't exist, because for common cases there are proper language constructs to select. C is a blunt axe, and only has pointer syntax, hence the problems and weird mitigations like &
« Last Edit: July 24, 2019, 10:40:54 am by marcov »

440bx

  • Hero Member
  • *****
  • Posts: 4014
Re: Is it possible to const an argument passed by reference in FPC?
« Reply #3 on: July 24, 2019, 10:51:45 am »
strings and dynamic arrays already contain an implicit ref.
For strings, that is only true when LONGSTRINGS ON is in effect and the parameter is not a shortstring. Otherwise, constref is required to declare the string is passed by reference (instead of value) and that it cannot be modified.

(FPC v3.0.4 and Lazarus 1.8.2) or (FPC v3.2.2 and Lazarus v3.2) on Windows 7 SP1 64bit.

ASerge

  • Hero Member
  • *****
  • Posts: 2240
Re: Is it possible to const an argument passed by reference in FPC?
« Reply #4 on: July 24, 2019, 11:40:06 am »
For strings, that is only true when LONGSTRINGS ON is in effect and the parameter is not a shortstring. Otherwise, constref is required to declare the string is passed by reference (instead of value) and that it cannot be modified.
Code: Pascal  [Select][+][-]
  1. {$APPTYPE CONSOLE}
  2. {$MODE OBJFPC}
  3.  
  4. procedure Test(const S: ShortString);
  5. begin
  6.   Writeln(S);
  7. end;
  8.  
  9. begin
  10.   Test('1');
  11. end.
FPC 3.0.4 x64
Code: ASM  [Select][+][-]
  1. .section .text.n_p$program_$$_test$shortstring,"x"
  2.         .balign 16,0x90
  3. .globl  P$PROGRAM_$$_TEST$SHORTSTRING
  4. P$PROGRAM_$$_TEST$SHORTSTRING:
  5. .Lc1:
  6. # Temps allocated between rbp-16 and rbp-8
  7. .seh_proc P$PROGRAM_$$_TEST$SHORTSTRING
  8. .Ll1:
  9. # [project1.lpr]
  10. # [5] begin
  11.         pushq   %rbp
  12. .seh_pushreg %rbp
  13. .Lc3:
  14. .Lc4:
  15.         movq    %rsp,%rbp
  16. .Lc5:
  17.         leaq    -48(%rsp),%rsp
  18. .seh_stackalloc 48
  19.         movq    %rbx,-16(%rbp)
  20. .seh_savereg %rbx, 32
  21. .seh_endprologue
  22. # Var S located at rbp-8, size=OS_64
  23.         movq    %rcx,-8(%rbp)
  24. .Ll2:
  25. # [6] Writeln(S);
  26.         call    fpc_get_output
  27. ...
  28. # [10] Test('1');
  29.         leaq    _$PROGRAM$_Ld1(%rip),%rax
  30.         movq    %rax,%rcx
  31.         call    P$PROGRAM_$$_TEST$SHORTSTRING
  32. .Ll7:
  33. # [11] end.
Same thing in x32. A short string is passed by reference. There is no allocation and copying inside the function.

440bx

  • Hero Member
  • *****
  • Posts: 4014
Re: Is it possible to const an argument passed by reference in FPC?
« Reply #5 on: July 24, 2019, 12:51:25 pm »
Same thing in x32. A short string is passed by reference. There is no allocation and copying inside the function.
No.  The reason you are getting that is because you specified "const" in the parameter, which for strings happens to be the same as specifying constref, therefore in that case, it causes the shortstring to be passed by reference but, while const works like constref for strings, it is not a reliable way of passing a parameter by reference.

From the Free Pascal Programmer's reference guide (page 192)
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.

That const worked in the example you provided is happenstance.

if you have code like this:
Code: Pascal  [Select][+][-]
  1. var
  2.   s : shortstring;
  3.  
  4. function DoString(p : string) : boolean;
  5. begin
  6.   p      := p + 'z';
  7.   result := true;
  8. end;
  9.  
  10. begin
  11.   s := 'abc';
  12.  
  13.   DoString(s);
  14.   writeln(s);  // prints abc, proving that the parameter s was passed by value.
  15.                // HOWEVER, you are correct that the parameter is passed by reference
  16.                // BUT a copy of the parameter is made thus making it the same as being passed by value
  17. end.
  18.  
you'll see that the compiler allocates a copy of the string
Code: ASM  [Select][+][-]
  1.                                   begin
  2. 00401560 55                       push   %ebp
  3. 00401561 89e5                     mov    %esp,%ebp
  4. 00401563 8da424f8feffff           lea    -0x108(%esp),%esp         ; allocate space for the short string
  5. 0040156A 8945fc                   mov    %eax,-0x4(%ebp)
  6. 0040156D 8b4dfc                   mov    -0x4(%ebp),%ecx
  7. 00401570 8d85f8feffff             lea    -0x108(%ebp),%eax
  8. 00401576 baff000000               mov    $0xff,%edx
  9. 0040157B e8300a0000               call   0x401fb0 <fpc_shortstr_to_shortstr>  ; copy it
  10.                                   p      := p + 'z';
  11. 00401580 680cb04000               push   $0x40b00c                 ; address of character 'z"
  12. 00401585 8d8df8feffff             lea    -0x108(%ebp),%ecx
  13. 0040158B 8d85f8feffff             lea    -0x108(%ebp),%eax
  14. 00401591 baff000000               mov    $0xff,%edx
  15. 00401596 e8a50d0000               call   0x402340 <fpc_shortstr_concat>  ; append character 'z" to COPY of string parameter
  16.                                   result := true;
  17. 0040159B b001                     mov    $0x1,%al
  18.                                           end;
  19. 0040159D c9                       leave  
  20. 0040159E c3                       ret    
  21.  
In 32bit, the called function copies the string.

In 64bit, here is the code:
Code: ASM  [Select][+][-]
  1.                                           begin
  2. 0000000100001610 55                       push   %rbp
  3. 0000000100001611 4889e5                   mov    %rsp,%rbp
  4. 0000000100001614 488d6424d0               lea    -0x30(%rsp),%rsp
  5. 0000000100001619 48895df8                 mov    %rbx,-0x8(%rbp)
  6. 000000010000161D e87e2c0000               callq  0x1000042a0 <fpc_initializeunits>
  7.                                           s := 'abc';
  8. 0000000100001622 488d05f7b90000           lea    0xb9f7(%rip),%rax        # 0x10000d020 <_$PROGRAM$_Ld2>
  9. 0000000100001629 488d0dd0d90000           lea    0xd9d0(%rip),%rcx        # 0x10000f000  - address of copy
  10. 0000000100001630 48baff00000000000000     movabs $0xff,%rdx
  11. 000000010000163A 4989c0                   mov    %rax,%r8
  12. 000000010000163D e83e060000               callq  0x100001c80 <fpc_shortstr_to_shortstr>
  13.                                           DoString(s);
  14. 0000000100001642 488d0db7d90000           lea    0xd9b7(%rip),%rcx        # 0x10000f000  - pass the address of the copy
  15. 0000000100001649 e862ffffff               callq  0x1000015b0 <DOSTRING>
  16.  
The 64bit code, unlike the 32bit code, makes a copy of the string and passes the copy to the function.  In the 32bit code it is the called function that makes a copy of the parameter.

for a C construct that specifies "const" and "&" (reference in C), the equivalent and reliable Pascal construct is "constref".  For strings, const just happens to work but, const may not be equivalent to "const" and "&" for other parameter types.


ETA:

You are correct that using "const" does work in the case of a string but, for anything that is meant to be constant and passed as a parameter, the clean, reliable way is to specify "constref", not const.

« Last Edit: July 24, 2019, 12:58:59 pm by 440bx »
(FPC v3.0.4 and Lazarus 1.8.2) or (FPC v3.2.2 and Lazarus v3.2) on Windows 7 SP1 64bit.

marcov

  • Administrator
  • Hero Member
  • *
  • Posts: 11444
  • FPC developer.
Re: Is it possible to const an argument passed by reference in FPC?
« Reply #6 on: July 24, 2019, 12:55:12 pm »
strings and dynamic arrays already contain an implicit ref.
For strings, that is only true when LONGSTRINGS ON is in effect and the parameter is not a shortstring. Otherwise, constref is required to declare the string is passed by reference (instead of value) and that it cannot be modified.

Const can also be by reference, if the ABI forces it. But yes, in hypothetical heavy shortstring usage where you want to forcedly avoid the case that it isn't, that is better.

I don't think I used shortstrings for anything in the last decade except maybe an isolated case where I used it as the key of a dictionary.

440bx

  • Hero Member
  • *****
  • Posts: 4014
Re: Is it possible to const an argument passed by reference in FPC?
« Reply #7 on: July 24, 2019, 01:04:30 pm »
But yes, in hypothetical heavy shortstring usage where you want to forcedly avoid the case that it isn't, that is better.
You were correct in what you stated in your first post.  "const" does work for strings to pass them as constants and by reference. I didn't realize that strings were one of the exceptions where "const" is the same as "constref".

From your previous post, I see that we agree on the fact that "constref" is the better and safe way to pass the parameter when const and by reference are needed instead of relying on exceptional cases the compiler makes.
(FPC v3.0.4 and Lazarus 1.8.2) or (FPC v3.2.2 and Lazarus v3.2) on Windows 7 SP1 64bit.

ikel

  • New Member
  • *
  • Posts: 26
Re: Is it possible to const an argument passed by reference in FPC?
« Reply #8 on: July 24, 2019, 01:46:55 pm »
Thanks everyone for the clarification.
It seems my takeaway are...

  • const on string works as constant and by reference
  • prefer constref is the better way to pass parameters when both are needed

@440bx, thanks for the comparison between 32 and 64 bit implementations. Very helpful to see what's happening behind the screen.

I feel working with FPC is a breath of fresh air.

ASerge

  • Hero Member
  • *****
  • Posts: 2240
Re: Is it possible to const an argument passed by reference in FPC?
« Reply #9 on: July 24, 2019, 02:10:40 pm »
By order. First @marcov say:
constref only makes a const argument forcedly by ref, but this is rarely used because strings and dynamic arrays already contain an implicit ref.
Code: Pascal  [Select][+][-]
  1. function isValidEntry(const input: string):boolean;
You you rejected it:
For strings, that is only true when LONGSTRINGS ON is in effect and the parameter is not a shortstring.
And after I made it clear that it was wrong, you agreed with @marcov.
No.  The reason you are getting that is because you specified "const" in the parameter, which for strings happens to be the same as specifying constref,
Good answer :(

marcov

  • Administrator
  • Hero Member
  • *
  • Posts: 11444
  • FPC developer.
Re: Is it possible to const an argument passed by reference in FPC?
« Reply #10 on: July 24, 2019, 02:17:32 pm »
Note that the refness of const depends on type and ABI.

That said, I only think the differences will be in reggable quantities, like GUID, for which constref was made (iunknown declaration).  It's 128-bit, but that is maybe reggable with 2 64-bits regs on some archs

lucamar

  • Hero Member
  • *****
  • Posts: 4219
Re: Is it possible to const an argument passed by reference in FPC?
« Reply #11 on: July 24, 2019, 02:32:48 pm »
Note that the refness of const depends on type and ABI.

Indeed, wasn't that one the reasons to introduce constref? To make absolutely sure that the parameter is passed as a strict reference?
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.

440bx

  • Hero Member
  • *****
  • Posts: 4014
Re: Is it possible to const an argument passed by reference in FPC?
« Reply #12 on: July 24, 2019, 02:40:06 pm »
For strings, that is only true when LONGSTRINGS ON is in effect and the parameter is not a shortstring.
That statement is 100% correct.

The reason I rejected it (or better stated, wanted to clarify it)
strings and dynamic arrays already contain an implicit ref.
There is NO implicit reference if a function parameter is a shortsting, either because of LONGSTRINGS OFF or explicitly specifying the type as shortstring and, neither const nor constref is specified, it will NOT be passed by reference, IOW, there is no implicit ref

And after I made it clear that it was wrong, you agreed with @marcov.
What I posted was not wrong at all.  It was and, still is correct.  The code I posted along with the disassembly proves it.  There is no implicit ref, the parameter will be copied, i.e, passed by value.

That said, you posted an example were you used "const" which for strings happens to be the same as "constref".  What you showed in the example/code you presented is correct BUT your example EXPLICITLY, by the use of "const," is indicating that the parameter is passed by reference.  It is NOT implicit as Marco stated.

No.  The reason you are getting that is because you specified "const" in the parameter, which for strings happens to be the same as specifying constref,
Good answer :(
Things got mixed up and I am in part responsible.  Marco, in his post, also referred to "const" which has the effect of passing the string by reference (as you showed) so I have to agree with that part. 

The part, which is the initial point I made, is that there is no implicit ref when passing strings when LONGSTRINGS is OFF or when passing a shortstring.

Hopefully, this is straight now.  There is no implicit ref when passing strings to a function either when LONGSTRINGS is OFF or the parameter is a shortstring.


ETA:

Note that the refness of const depends on type and ABI.
That's part of the problem too.  The Programmer's reference guide warns about "const" not meaning "pass by reference" (as it is in Delphi) but, it doesn't say anything about when it implies "pass by reference" and when it doesn't. Basically, if you want to know, look at the assembly code and figure it out yourself.
« Last Edit: July 24, 2019, 02:47:50 pm by 440bx »
(FPC v3.0.4 and Lazarus 1.8.2) or (FPC v3.2.2 and Lazarus v3.2) on Windows 7 SP1 64bit.

PascalDragon

  • Hero Member
  • *****
  • Posts: 5462
  • Compiler Developer
Re: Is it possible to const an argument passed by reference in FPC?
« Reply #13 on: July 25, 2019, 09:55:53 am »
Note that the refness of const depends on type and ABI.
That's part of the problem too.  The Programmer's reference guide warns about "const" not meaning "pass by reference" (as it is in Delphi) but, it doesn't say anything about when it implies "pass by reference" and when it doesn't. Basically, if you want to know, look at the assembly code and figure it out yourself.
Also the behaviour of const might change with each version of FPC as it's not part of the platform ABI, thus it might be that in some newer version it's decided to pass a parameter type in a more optimal way.

440bx

  • Hero Member
  • *****
  • Posts: 4014
Re: Is it possible to const an argument passed by reference in FPC?
« Reply #14 on: July 25, 2019, 10:01:56 am »
Also the behaviour of const might change with each version of FPC as it's not part of the platform ABI, thus it might be that in some newer version it's decided to pass a parameter type in a more optimal way.
I don't know if you will agree or not but, personally, I think that "const" should never be used with parameters.  "var" and "constref", yes, because they are well defined. "const" no, because its meaning is, in addition to being anyone's guess, as you pointed out it might change in the future.

If it weren't needed for Delphi compatibility, I'd even suggest not allowing "const" with parameters.
(FPC v3.0.4 and Lazarus 1.8.2) or (FPC v3.2.2 and Lazarus v3.2) on Windows 7 SP1 64bit.

 

TinyPortal © 2005-2018