Re: [fpc-devel] Maybe room for better documentation? open array as var param
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
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
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
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
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