Re: [fpc-devel] Maybe room for better documentation? open array as var param

2023-07-23 Thread Martin via fpc-devel

On 20/07/2023 18:41, Martin Frb via fpc-devel wrote:
For const param, it is well documented that the value (that includes 
the variable that is passed) must not be changed.


But for "var param"?


Actually my previous example was not even the generic case.

Passing any variable that is allocated on the Heap (a field of an 
instance, an element of an array) as a "var param" has the danger that 
it can be freed.


And yes, it should be obvious. If you intent to write to a variable, you 
must not destroy it.
However, you must also be aware, that in case of an array, if you just 
resize it, it may move => yet your var param will not follow that move.


I think it may be "interesting" enough to deserve a small note.

--
The below should brinte 200 to 209.
But it does print a 999 in the middle.




program Project1;
{$mode objfpc}

var x,y: array of integer;
  i: Integer;

procedure foo(var a: integer);
var
  j: Integer;
begin
  x := nil;
  SetLength(y, 10);
  for j := 0 to 9 do y[j] := 200+j;

  a := 999;
end;

begin
  SetLength(x, 10);
  for i := 0 to 9 do x[i] := 100+i;
  foo(x[5]);
  for i := 0 to 9 do writeln(y[i]);
  readln;
end.

___
fpc-devel maillist  -  fpc-devel@lists.freepascal.org
https://lists.freepascal.org/cgi-bin/mailman/listinfo/fpc-devel


Re: [fpc-devel] Maybe room for better documentation? open array as var param

2023-07-20 Thread Michael Van Canneyt via fpc-devel




On Thu, 20 Jul 2023, Sven Barth via fpc-devel wrote:



It's IMO probably better to outright forbid passing open array by
reference.



There are valid use cases for that. E.g. multiply a slice of a dynamic
array by two or whatever. And forbidding var would solve nothing, see
below.


printing length(a) after x:=Nil; gives 10, which is simply wrong.



That is true for many cases where you modify the global variable that has
been passed on by reference, e.g. with constant parameters: the compiler
will more often than not pass a reference then, because it's more optional
and the function can't modify it anyway, but if you change the global that
was passed in you get what you deserve... (that's true no matter if it's an
open array, a string or a primitive type).


Valid point...

I will document the behaviour with the example Martin made.

Michael.
___
fpc-devel maillist  -  fpc-devel@lists.freepascal.org
https://lists.freepascal.org/cgi-bin/mailman/listinfo/fpc-devel


Re: [fpc-devel] Maybe room for better documentation? open array as var param

2023-07-20 Thread Sven Barth via fpc-devel
Michael Van Canneyt via fpc-devel  schrieb
am Do., 20. Juli 2023, 19:24:

>
>
> On Thu, 20 Jul 2023, Martin Frb via fpc-devel wrote:
>
> > For const param, it is well documented that the value (that includes the
> > variable that is passed) must not be changed.
> >
> > But for "var param"?
> >
> > Well maybe, but not explicit
> > https://www.freepascal.org/docs-html/ref/refsu68.html#x184-20800014.4.5
> > >> Open parameters can be passed by value, by reference or as a
> > constant parameter. In the latter cases the procedure receives a pointer
> > to the actual array.
> >
> > So a user with sufficient experience could detect that if a pointer is
> > received, then the value which is pointed to must not be changed.
> >
> > Maybe that should be mentioned more explicitly.
> > And maybe it should additionally also be mentioned on
> > https://www.freepascal.org/docs-html/ref/refsu65.html
> >
> >
> > Because the below may be unexpected to quite a few users.
> >
> > It will (at least on my test on windows / of course depends on mem
> > manager) print numbers starting at 300.
> > Even so 200++ has been assigned.
> >
> > But (with sufficient luck or lack of luck) "y" will re-use the memory of
> > "x". And "a" will then change "y" which may not be expected.
> >
> >
> > program Project1;
> > {$mode objfpc}
> >
> > var x,y: array of integer;
> >   i: Integer;
> >
> > procedure foo(var a: array of integer);
> > var
> >   j: Integer;
> > begin
> >   x := nil;
> >   SetLength(y, 10);
> >   for j := 0 to 9 do y[j] := 200+j;
> >
> >   for j := 0 to 9 do a[j] := 300+j;
> > end;
> >
> > begin
> >   SetLength(x, 10);
> >   for i := 0 to 9 do x[i] := 100+i;
> >   foo(x);
> >   for i := 0 to 9 do writeln(y[i]);
> >   readln;
> > end.
>
> It's IMO probably better to outright forbid passing open array by
> reference.
>

There are valid use cases for that. E.g. multiply a slice of a dynamic
array by two or whatever. And forbidding var would solve nothing, see
below.


> printing length(a) after x:=Nil; gives 10, which is simply wrong.
>

That is true for many cases where you modify the global variable that has
been passed on by reference, e.g. with constant parameters: the compiler
will more often than not pass a reference then, because it's more optional
and the function can't modify it anyway, but if you change the global that
was passed in you get what you deserve... (that's true no matter if it's an
open array, a string or a primitive type).

Regards,
Sven

>
___
fpc-devel maillist  -  fpc-devel@lists.freepascal.org
https://lists.freepascal.org/cgi-bin/mailman/listinfo/fpc-devel


Re: [fpc-devel] Maybe room for better documentation? open array as var param

2023-07-20 Thread Martin Frb via fpc-devel

On 20/07/2023 19:24, Michael Van Canneyt via fpc-devel wrote:



It's IMO probably better to outright forbid passing open array by 
reference.


printing length(a) after x:=Nil; gives 10, which is simply wrong.


The open array is not the same as the dyn array.

It is at any point just a slice of the dyn array. (even if the slice has 
all elements of the dyn array).
At no point is it possible to do a SetLength on the open array (and 
therefore the lenght of the dyn array can't be changed either - not via 
the open array).


In otherwise the reference is only a reference to the members.
There is at no point a reference to the dyn array itself, nor to the length.


Of course if the underlaying data goes away, then the "var param" open 
array  (same as "const param") points to some memory


I don't know if it needs to be forbidden (don't mind if).
But I think
- explicit documentation
- a compiler note or warning might be helpful


___
fpc-devel maillist  -  fpc-devel@lists.freepascal.org
https://lists.freepascal.org/cgi-bin/mailman/listinfo/fpc-devel


Re: [fpc-devel] Maybe room for better documentation? open array as var param

2023-07-20 Thread Michael Van Canneyt via fpc-devel



On Thu, 20 Jul 2023, Martin Frb via fpc-devel wrote:

For const param, it is well documented that the value (that includes the 
variable that is passed) must not be changed.


But for "var param"?

Well maybe, but not explicit
https://www.freepascal.org/docs-html/ref/refsu68.html#x184-20800014.4.5
>> Open parameters can be passed by value, by reference or as a 
constant parameter. In the latter cases the procedure receives a pointer 
to the actual array.


So a user with sufficient experience could detect that if a pointer is 
received, then the value which is pointed to must not be changed.


Maybe that should be mentioned more explicitly.
And maybe it should additionally also be mentioned on 
https://www.freepascal.org/docs-html/ref/refsu65.html



Because the below may be unexpected to quite a few users.

It will (at least on my test on windows / of course depends on mem 
manager) print numbers starting at 300.

Even so 200++ has been assigned.

But (with sufficient luck or lack of luck) "y" will re-use the memory of 
"x". And "a" will then change "y" which may not be expected.



program Project1;
{$mode objfpc}

var x,y: array of integer;
  i: Integer;

procedure foo(var a: array of integer);
var
  j: Integer;
begin
  x := nil;
  SetLength(y, 10);
  for j := 0 to 9 do y[j] := 200+j;

  for j := 0 to 9 do a[j] := 300+j;
end;

begin
  SetLength(x, 10);
  for i := 0 to 9 do x[i] := 100+i;
  foo(x);
  for i := 0 to 9 do writeln(y[i]);
  readln;
end.


It's IMO probably better to outright forbid passing open array by reference.

printing length(a) after x:=Nil; gives 10, which is simply wrong.

Michael.___
fpc-devel maillist  -  fpc-devel@lists.freepascal.org
https://lists.freepascal.org/cgi-bin/mailman/listinfo/fpc-devel