2
votes

If I have a record e.g.

type
  TMyRec = record
    x : string;
  end;

And a procedure test(const x : TMyRec);. Why is that parameter passed by value (i.e. a copy is passed in) and not by reference. I would have thought from an efficiency point of view it should be passed by reference (like say an integer).

1
Because of the record's size. This is explained in program control.Sertac Akyuz
This is basically the whole purpose of records. You can optionally pass it as a pointer, if you wish.Jerry Dodge
Why would it be more efficient that way?David Heffernan
Passing by reference would probably be more efficient for large records (no need to copy), but for small records like this, passing by reference would most definitelly be less efficient (indirect access instead of direct access).Rudy Velthuis
@David: indeed. That is why pass by value for this record is not more efficient . On the contrary to what Alister thought, it is less efficient.Rudy Velthuis

1 Answers

6
votes

It looks like this is related to the size of the record, for

procedure test(const x : TMyRec);

the type

type
  TMyRec = record
    x : Array[1..4] of byte;
  end;

would be passed by value, and

type
  TMyRec = record
    x : Array[1..5] of byte
  end;

would be passed by reference on 32 bit, for 64 bit we would need a record of 9 bytes to be passed by reference on Tokyo (10.2.3) or earlier, Rio (10.3) behaves the same on both 32 and 64 bit. Thanks to everyone who comment on my question, and provided additional references/suggestions.

See the Tokyo Documentation here. In particular

Value and constant (const) parameters are passed by value or by reference, depending on the type and size of the parameter:

...

Sets, records, and static arrays of 1, 2, or 4 bytes are passed as 8-bit, 16-bit, and 32bit values. Larger sets, records, and static arrays are passed as 32-bit pointers to the value. An exception to this rule is that records are always passed directly on the stack under the cdecl, stdcall, and safecall conventions; the size of a record passed this way is rounded upward to the nearest double-word boundary.

If you want to force a pass-by-reference, you can declare your parameter as const [ref], like so:

procedure test(const [ref] x : TMyRec);