Recent

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

ASerge

  • Hero Member
  • *****
  • Posts: 2246
Re: Is it possible to const an argument passed by reference in FPC?
« Reply #15 on: July 25, 2019, 10:55:40 am »
"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.
Still, pascal is not an assembler. The level of abstraction allows you not to think about implementation. But the const modifier avoids errors when the input parameter changes inside the function.
I would have changed the approach. The default is to consider all the parameters are const by default. I.e. it is impossible to assign them something. If want to change, declare a local variable and assign to it. In this case, the const modifier could be omitted. And there are languages where the input parameter cannot be changed if it is not explicitly declared changeable (var in Pascal).

440bx

  • Hero Member
  • *****
  • Posts: 4063
Re: Is it possible to const an argument passed by reference in FPC?
« Reply #16 on: July 25, 2019, 12:54:04 pm »
But the const modifier avoids errors when the input parameter changes inside the function.
If the const modifier had a consistent and predictable behavior, I would completely agree with that statement.  Unfortunately, in FPC, the behavior of the "const" modifier isn't really consistent and predictable.  For that reason, I don't use it.  In addition to that, considering that its semantics may change in a future implementation of FPC, using it invites introducing future incompatibilities.

All that said, if the const modifier always meant "constant" and nothing else then, I could agree with your statement without reservations.

The default is to consider all the parameters are const by default. I.e. it is impossible to assign them something. If want to change, declare a local variable and assign to it. In this case, the const modifier could be omitted. And there are languages where the input parameter cannot be changed if it is not explicitly declared changeable (var in Pascal).
I think that is quite sensible and would make the code more robust.
(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: 11455
  • FPC developer.
Re: Is it possible to const an argument passed by reference in FPC?
« Reply #17 on: July 25, 2019, 01:58:08 pm »
But the const modifier avoids errors when the input parameter changes inside the function.
If the const modifier had a consistent and predictable behavior, I would completely agree with that statement.  Unfortunately, in FPC, the behavior of the "const" modifier isn't really consistent and predictable.  For that reason, I don't use it.  In addition to that, considering that its semantics may change in a future implementation of FPC, using it invites introducing future incompatibilities.

Simple. The few places where it (due to external interfaces) must be fixated, use constref. For the rest, use const.
 

440bx

  • Hero Member
  • *****
  • Posts: 4063
Re: Is it possible to const an argument passed by reference in FPC?
« Reply #18 on: July 25, 2019, 02:54:07 pm »
Simple. The few places where it (due to external interfaces) must be fixated, use constref. For the rest, use const.
If any of the FPC manuals was clear and unequivocal about the behavior of "const" under which conditions then, I would use it but, the FPC manuals are rather wishy-washy as to what "const" may or may not do, for that reason, I don't trust it, therefore I don't use it.

Also, after this statement from PascalDragon:
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 am even less inclined to use it.

I'm fine with constref or passing by value.  Not quite the same but, safe and predictable.
(FPC v3.0.4 and Lazarus 1.8.2) or (FPC v3.2.2 and Lazarus v3.2) on Windows 7 SP1 64bit.

Zoran

  • Hero Member
  • *****
  • Posts: 1831
    • http://wiki.lazarus.freepascal.org/User:Zoran
Re: Is it possible to const an argument passed by reference in FPC?
« Reply #19 on: July 25, 2019, 03:07:23 pm »
Simple. The few places where it (due to external interfaces) must be fixated, use constref. For the rest, use const.
If any of the FPC manuals was clear and unequivocal about the behavior of "const" under which conditions then, I would use it but, the FPC manuals are rather wishy-washy as to what "const" may or may not do, for that reason, I don't trust it, therefore I don't use it.

Also, after this statement from PascalDragon:
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 am even less inclined to use it.
No, what PascalDragon said is not that.
The meaning of const will not change in future versions.
But you should understand well that the meaning of const has nothing to do about whether it is passed by reference or by value.

Unless for some reason you need to know whether it will be passed by value or by reference (and you would very rarely need to know it, why would you?), use const and the compiler will make the decision how it will be passed and try to decide what is more optimal.
Only that decision is what may change, but it actually has nothing to do with const's meaning in fpc.

When you want to force the compiler to pass by refernce, use var.

The combination of these two unrelated things (parameter which are not allowed to be changed in procedure body, and passing by reference) is very rarely needed.
Why would you need to force passing by reference, why would you care how will it be passed, if you do not intend to change the parameter?

When for some reason (external interfaces as Marco says, and hardly anything else) you need these two unrelated things, there you can use constref.

lucamar

  • Hero Member
  • *****
  • Posts: 4219
Re: Is it possible to const an argument passed by reference in FPC?
« Reply #20 on: July 25, 2019, 03:13:49 pm »
I would have changed the approach. The default is to consider all the parameters are const by default. I.e. it is impossible to assign them something. If want to change, declare a local variable and assign to it. In this case, the const modifier could be omitted. And there are languages where the input parameter cannot be changed if it is not explicitly declared changeable (var in Pascal).

That would break quite a lot of code bases. I've used languages which do what you say and it's a small nigtmare: first thing you do, almost automatically, is move the parameters to local variables, with the subsequent waste of stack/memory.

I prefer "the Pascal way" where unqualified params are basically local vars which happen to be initialized on the call and where you mark deviations of this norm with var, const, out, etc.
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: 4063
Re: Is it possible to const an argument passed by reference in FPC?
« Reply #21 on: July 25, 2019, 03:53:11 pm »
The meaning of const will not change in future versions.
You are interpreting what PascalDragon said a different way than I am.  He said :
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.
To me that means, the meaning of const is not fixed, there is no guarantee that const will behave in one version the same way it behaves in another.  For me, that is more than enough not to use it.

But you should understand well that the meaning of const has nothing to do about whether it is passed by reference or by value.
It shouldn't but, unfortunately it does.  Sometimes "const" means a parameter passed by reference which cannot be used as an l-value and, some other times, it only means "constant".

Borland is responsible for muddying that water by associating semantics to const that have nothing to do with declaring a parameter is constant.

Unless for some reason you need to know whether it will be passed by value or by reference (and you would very rarely need to know it, why would you?)
There are quite a few times when you _really_ need to know.  Here is an example, the buffer parameter of the WriteFile windows API is declared as "const buffer" (untyped).  I was porting some C code to FPC, I pass the pointer to my buffer to WriteFile and I'm getting garbage out.  I look at the code and it's perfectly fine, in full accordance with how WriteFile is documented.  After a little bit of digging, I find that FPC is passing a pointer to my buffer pointer (pointer to pointer) instead of just the pointer to my buffer, that because of "const". 

"Solution:" if you have a pointer to a buffer you want to pass to WriteFile, you have to dereference the pointer, which should not be necessary (at least as documented in MSDN) and, forgetting to dereference the pointer will reward you with either garbage or even possibly an access violation in some cases.

The behavior of "const", when used as a parameter modifier, is not precisely and accurately defined, for that reason, it's only a source of headaches.

« Last Edit: July 25, 2019, 05:04:34 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.

ASerge

  • Hero Member
  • *****
  • Posts: 2246
Re: Is it possible to const an argument passed by reference in FPC?
« Reply #22 on: July 25, 2019, 05:01:57 pm »
That would break quite a lot of code bases.
Something like {$IMPLICITCONST ON}

Quote
I've used languages which do what you say and it's a small nigtmare: first thing you do, almost automatically, is move the parameters to local variables, with the subsequent waste of stack/memory.
You always change input parameters?

lucamar

  • Hero Member
  • *****
  • Posts: 4219
Re: Is it possible to const an argument passed by reference in FPC?
« Reply #23 on: July 25, 2019, 05:31:23 pm »
You always change input parameters?

Not always, no. Not even in most cases, now. But sometimes it just happens that the parameter is the more apropriate var to use. For example, if you have a function declared like, say, PosEx(), its Offset parameter might be handy to iterate through a string/array doing whatever it does and it's already initialized to the desired starting value.

Of course, it depends on what the function does and how, but having that "local" var already init'ed and waiting to be be used is sometimes a nice bonus.

The question is not really one of "changing parameters" but of using them as "local vars" (which, after all, they basicaly are)
« Last Edit: July 25, 2019, 05:40:22 pm by lucamar »
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: 1831
    • http://wiki.lazarus.freepascal.org/User:Zoran
Re: Is it possible to const an argument passed by reference in FPC?
« Reply #24 on: July 25, 2019, 05:54:35 pm »
The meaning of const will not change in future versions.
You are interpreting what PascalDragon said a different way than I am.  He said :
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.
To me that means, the meaning of const is not fixed, there is no guarantee that const will behave in one version the same way it behaves in another.  For me, that is more than enough not to use it.

As I understand, it means that what might change is how compiler makes decision whether to pass a const parameter -- by value or by reference.

What does not change is the fact which is clearly documented -- that it is not guaranteed how parameter will be passed and that you must not assume that it is passed by reference.

So, what can change is just implementation detail, nothing else.
This is how I understand what PascalDragon meant. I hope he will see this and clarify what he meant.

But you should understand well that the meaning of const has nothing to do about whether it is passed by reference or by value.
It shouldn't but, unfortunately it does.  Sometimes "const" means a parameter passed by reference

Not in FPC. It only means that it is constant. How it is passed is implementation detail (as such, it can change in future, if you don't rely on it, you will never encounter bad surprises).

If by "sometimes", you mean Delphi vs FPC, then yes, here FPC and Delphi are different (which is also clearly documented).

Borland is responsible for muddying that water by associating semantics to const that have nothing to do with declaring a parameter is constant.

True, but here FPC developers decided not to follow Delphi blindly. So, in FPC const means that it is constant, nothing else. This will not change in future versions.

Unless for some reason you need to know whether it will be passed by value or by reference (and you would very rarely need to know it, why would you?)
There are quite a few times when you _really_ need to know.  Here is an example, the buffer parameter of the WriteFile windows API is declared as "const buffer" (untyped).  I was porting some C code to FPC, I pass the pointer to my buffer to WriteFile and I'm getting garbage out.  I look at the code and it's perfectly fine, in full accordance with how WriteFile is documented.  After a little bit of digging, I find that FPC is passing a pointer to my buffer pointer (pointer to pointer) instead of just the pointer to my buffer, that because of "const". 

Then it is wrongly declared, it is wrong translation of win api header.
Where is it declared? If in FPC sources, this is a bug which should be reported.
If third party, then it might have been translated to be used with Delphi, and yes, we know that const parameter passing is not compatible with FPC.

With external routines we truly have to know how parameters are passed. So, yes, const parameters should be avoided in external declarations. There you have the point. Don't use it there.

lucamar

  • Hero Member
  • *****
  • Posts: 4219
Re: Is it possible to const an argument passed by reference in FPC?
« Reply #25 on: July 25, 2019, 11:50:40 pm »
But somewhere in time not so long ago someone decided to allow the compiler to make choices on its own about how the parameters are to be past onto the function.

Compilers have always made their own choices about the "mechanics" of parameter-passing. If you look carefully, most of the times it's documented it is in a section about interfacing with assembler or other languages.

A different (though somehat related) question is what the parser should flag as an error in the source code (or should trigger an error at run-time); like for example, trying to write to a const parameter. That's a question of "semantics", i.e. of what a certain syntactic construction *means*, regardless of how it's implemented.
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: 4063
Re: Is it possible to const an argument passed by reference in FPC?
« Reply #26 on: July 26, 2019, 01:58:15 am »
With external routines we truly have to know how parameters are passed. So, yes, const parameters should be avoided in external declarations. There you have the point. Don't use it there.
Strictly speaking, there should be no reason for avoiding "const" in external declarations.  If "const" always meant _only_ "constant" (as it's supposed to) then it could be used anywhere just fine.

I don't want to use something that isn't consistent and 100% predictable.  I just tested it with an internal function and, as you stated, it did _not_ cause the parameter to be passed by reference but, the same definition found in WriteFile causes the parameter to be passed by reference.   Stuff that does that goes directly into my "never use bucket".  AFAIC, "const" for parameters doesn't exist.


ETA:

Another reason for my avoiding "const" with parameters is that, whenever possible, I try to make my code compatible with Delphi and FPC.  If one construct works one way with one compiler and a different way in the other, I will do everything reasonably possible to avoid it.  I also, don't want my code peppered with {$ifdef FPC} or equivalent for Delphi, unless absolutely necessary.


« Last Edit: July 26, 2019, 02:19:47 am 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: 5486
  • Compiler Developer
Re: Is it possible to const an argument passed by reference in FPC?
« Reply #27 on: July 26, 2019, 09:17:12 am »
The meaning of const will not change in future versions.
You are interpreting what PascalDragon said a different way than I am.  He said :
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.
To me that means, the meaning of const is not fixed, there is no guarantee that const will behave in one version the same way it behaves in another.  For me, that is more than enough not to use it.

As I understand, it means that what might change is how compiler makes decision whether to pass a const parameter -- by value or by reference.

What does not change is the fact which is clearly documented -- that it is not guaranteed how parameter will be passed and that you must not assume that it is passed by reference.

So, what can change is just implementation detail, nothing else.
This is how I understand what PascalDragon meant. I hope he will see this and clarify what he meant.
You're correct. The "constness" of const parameters is guaranteed, how the parameters are passed, is not. In theory the compiler and optimizer would be free to change the passing of const parameters* of specific method if it's known that the function is not exported and using e.g. registers instead of the stack would optimize the program. Though such an optimization would probably need to be part of WPO to really pay off.

* It could also be applied for any parameters, but for those the compiler/optimizer would need to ensure that the by-value/by-ref semantic is kept, which is not the case for const.

But you should understand well that the meaning of const has nothing to do about whether it is passed by reference or by value.
It shouldn't but, unfortunately it does.  Sometimes "const" means a parameter passed by reference

Not in FPC. It only means that it is constant. How it is passed is implementation detail (as such, it can change in future, if you don't rely on it, you will never encounter bad surprises).

If by "sometimes", you mean Delphi vs FPC, then yes, here FPC and Delphi are different (which is also clearly documented).
Again correct as mentioned in the documentation.

Unless for some reason you need to know whether it will be passed by value or by reference (and you would very rarely need to know it, why would you?)
There are quite a few times when you _really_ need to know.  Here is an example, the buffer parameter of the WriteFile windows API is declared as "const buffer" (untyped).  I was porting some C code to FPC, I pass the pointer to my buffer to WriteFile and I'm getting garbage out.  I look at the code and it's perfectly fine, in full accordance with how WriteFile is documented.  After a little bit of digging, I find that FPC is passing a pointer to my buffer pointer (pointer to pointer) instead of just the pointer to my buffer, that because of "const". 

"Solution:" if you have a pointer to a buffer you want to pass to WriteFile, you have to dereference the pointer, which should not be necessary (at least as documented in MSDN) and, forgetting to dereference the pointer will reward you with either garbage or even possibly an access violation in some cases.

The behavior of "const", when used as a parameter modifier, is not precisely and accurately defined, for that reason, it's only a source of headaches.
You are mixing the behaviour of typed const parameters and untyped ones. It's not clearly documented (that can definitely be improved), but it's by design that you need to dereference pointers if you want to pass their contents to an untyped var or const parameter. It's the same for FillChar and Move for example (they're not special functions after all, they simply rely on the semantics of untyped parameters).

440bx

  • Hero Member
  • *****
  • Posts: 4063
Re: Is it possible to const an argument passed by reference in FPC?
« Reply #28 on: July 26, 2019, 09:48:43 am »
You are mixing the behaviour of typed const parameters and untyped ones. It's not clearly documented (that can definitely be improved), but it's by design that you need to dereference pointers if you want to pass their contents to an untyped var or const parameter. It's the same for FillChar and Move for example (they're not special functions after all, they simply rely on the semantics of untyped parameters).
I'm not surprised I'm mixing them.  As you pointed out, the behavior of const with or without untyped parameters is "not clearly documented".  In addition to that, it really doesn't seem to be consistent either.  Take this example:
Code: Pascal  [Select][+][-]
  1. procedure DoConstBuffer(const Buffer); stdcall;  // the calling convention makes no difference
  2. begin
  3.   writeln;
  4.   writeln('in DoConstBuffer');
  5.   writeln(IntToHex(ptruint(Buffer), 0));  // writes 0 (nil)
  6. end;
  7.  
  8. var
  9.   Buffer : pointer = nil;
  10.  
  11.  
  12. begin
  13.   writeln('  value of Buffer : ', IntToHex(ptruint(Buffer), 0));
  14.   writeln('address of Buffer : ', IntToHex(ptruint(@Buffer), 0));
  15.  
  16.   DoConstBuffer(Buffer);
  17. end.
  18.  
You run that code and what's passed to DoConstBuffer is the value of Buffer (in this example, nil).  The WriteFile Windows API has the Buffer parameter defined exactly as it is in DoConstBuffer, yet, what is passed is a pointer to the Buffer.  IOW, what's passed to WriteFile is @Buffer, not the value of Buffer.

I don't see why it behaves differently in that case but, when I see stuff like that, my conclusion is: don't use const because what it's going to do is unpredictable.

One thing that is probably worth mentioning is that the definition of WriteFileEx does not use a "const untyped", instead it specifies the parameter as "ParameterName : pointer", thereby making dereferencing unnecessary and, converting a WriteFile to a WriteFileEx (to do asynchronous I/O) a gratuitously error prone operation.




(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: 5486
  • Compiler Developer
Re: Is it possible to const an argument passed by reference in FPC?
« Reply #29 on: July 27, 2019, 10:41:16 am »
I don't see why it behaves differently in that case but, when I see stuff like that, my conclusion is: don't use const because what it's going to do is unpredictable.
It behaves exactly as it's designed to behave: untyped parameters alway pass the address of what you passed in (that's why you can't use constant values for example on those parameters). This indeed - as I already wrote - can and should be explained better in the documentation.

 

TinyPortal © 2005-2018