I've been reading about the various means of passing parameters to procedures and functions, but I am still confused about the semantics of var and constref as they apply to records (this is regarding the Free Pascal dialect of the language, v3.x).
My understanding is that:
var and constref enforce that a parameter is passed by referencevar suggests mutation of the argument is possible, while const[ref] does notThis distinction makes sense for simple types such as numbers and strings, but what about structured types? Assuming I have the following record:
A = record
x: Integer;
end;
And a procedure that acts on As like the following:
procedure proc(var rec: A);
begin
rec.x := 42;
end;
i.e. proc does not reassign rec, but it does perform a side-effect in that it mutates fields of its formal parameter. I was able to compile this just fine under fpc 3.0.4 with either var or constref, but my gut feeling is that rec should probably be declared as var here so as to indicate that the memory occupied by this record instance is changed by the procedure call?
In other words, should I use constref whenever I do not reassign a formal parameter and I want to enforce passing a record by reference, or only when that record is also truly immutable in the sense that the procedure does not write to any of its fields either? But also, what is the difference from the perspective of the compiler, since apparently it does not catch the fact that even with constref I am able to mutate fields of a record that is passed by reference?
UPDATE:
As the responder points out, the above sample code should (and does) fail to compile with fpc 3.x; I had oversimplified. In my case, the A record was holding references to dynamic arrays, and it was those array elements that I was able to reassign through a constref parameter, which confused me:
A = record
x: Array of Integer;
end;
procedure proc(constref rec: A);
begin
rec.x[0] := 42; // this works
end;
It sounds like the reason is that a dynamic array is essentially just a pointer, and arr[i] is syntactic sugar to dereference that pointer.
The documentation to which you link explains that constref differs from const only in that constref arguments are always passed by reference, whereas const arguments can be passed by reference or value as determined by the compiler.
So, this code
procedure proc(constref rec: A);
begin
rec.x := 42;
end;
should result in a compilation error. When I attempt to compile this in the versions of fpc available at https://godbolt.org/ (2.6.0, 2.6.2, 2.6.4, 3.0.2, 3.0.4 and 3.2.0) the compiler rejects it as invalid in all cases.
If this code compiles in your installation of fpc 3.0.4 then that is a compiler bug that should be reported. However, that seems at odds with what I have observed, so I suggest that you carefully re-check your findings.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With