I'm not sure if I understand correctly how pass by reference in Pascal works. Does it create an alias as in C++ (https://isocpp.org/wiki/faq/references) or does it work similarly as in C and the procedure gets a pointer to the variable and uses this pointer.
I guess I could formulate my question as: Does Pascal support true passing by reference, or is it done by call by sharing.
For example FreePascal reference states, that the procedure gets a pointer (https://www.freepascal.org/docs-html/current/ref/refsu65.html), but according to https://swinbrain.ict.swin.edu.au/wiki/Pass_by_Value_vs._Pass_by_Reference#Conclusion and for example https://cgi.csc.liv.ac.uk/~frans/OldLectures/2CS45/paramPassing/paramPassing.html#callByReference pass by reference in Pascal works differently than in C (where pointer is passed).
If anyone can explain a bit more about the differences or how the meaning of pass by reference has changed (in modern languages we say pass by reference, but in fact they are pass by value, like for example Java). What is then the original meaning of pass by reference and how does it work? And how is it then in Pascal?
Thank you very much.
in Delphi, pass by reference (using var or out) means passing a pointer. But note that there is a difference between the semantics "pass by value" or "pass by reference" and the actual passing.
The difference with C is not the actual passing (by pointer), just what these keywords mean. Var simply passes by reference. Out treats certain managed types differently, because with out, you tell the compiler the input value is not guaranteed to be initialized. Otherwise, these are technically the same (but not semantically): the address of (IOW, a pointer to) the original values is passed.
But the actually generated code may be different, for reasons of optimization. Especially larger structures (how large depends on version and platform -- this is documented somewhere and has changed over time) are often passed by reference (as pointers) even if the semantics say pass by value. In the prologue of the routine (the hidden code that runs before the first begin
) such structures are then copied to the local frame of the routine. Note that this is not done in all calling conventions. Sometimes a full copy is made to the parameter stack before the call and no pointer is passed.
Since you still have a local copy, and don't modify the original, this is still considered pass by value, just like you declared. All the technical stuff happens transparently for the user, so the difference is only at a lower level. This only matters if you write assembler or must read generated code in the CPU window.
If a value parameter is declared const
, the original is not modified anyway, so the copying of a large structure to the local frame may be omitted and the values can accessed (read-only) by reference (pointer), even if the semantics are pass by value. Small values are always passed by value (in a register or on the stack), in such cases.
Although it doesn't make sense to have const var
as parameter modifier (something is either constant or variable, but not both), you can still force the passing by reference of a const
parameter, by using the [ref]
modifier attribute: const [ref] X: Integer
or [ref] const X: Integer
. The integer would usually be passed by value (in a register or on the stack, depending on calling convention and platform).
Note that if you pass reference types (e.g. objects, dynamic arrays, etc.) by value, the pass by value semantics only apply to the references themselves, i.e. you get a copy of them and you can modify the reference without affecting the original.
BUT: the items (objects, arrays, etc.) to which these references point can be modified. Only the references themselves are local copies, not to what they point. So if you call a method on an object reference passed by value, that object (on the heap) may be modified after all! That is not because pass-by-value or pass-as-const do not work properly, but because of what references are.
A little more about references and pointers can be found in my (very popular) article Addressing pointers.