11

With the latest Delphi version (Berlin/10.1/24), is the [Ref] attribute really necessary?

I ask this because the online doc says:

Constant parameters may be passed to the function by value or by reference, depending on the specific compiler used. To force the compiler to pass a constant parameter by reference, you can use the [Ref] decorator with the const keyword.

Ken White
  • 123,280
  • 14
  • 225
  • 444
  • 1
    You may find the answer here: [Can I force `const` to pass by reference (aka the missing `in` parameter)](http://stackoverflow.com/q/19094375/576719). – LU RD Dec 02 '16 at 10:06
  • 1
    That is, const records <= SizeOf(pointer) are passed by value. If you want to ensure that a reference is passed, use the [ref] attribute. – LU RD Dec 02 '16 at 10:14
  • ok that sounds very sensible, and makes me think I can give up on using the Ref attribute for const record parameters. –  Dec 02 '16 at 10:17

2 Answers2

12

It's pretty much as described by the documentation. You'd use [ref] if you had a reason to enforce the argument to be passed by reference. One example that I can think of is for interop. Imagine you are calling an API function that is defined like this:

typedef struct {
    int foo;
} INFO;

int DoStuff(const INFO *lpInfo);

In Pascal you might wish to import it like this:

type
  TInfo = record
    foo: Integer;
  end;

function DoStuff(const Info: TInfo): Integer; cdecl; external libname;

But because TInfo is small, the compiler might choose to pass the structure by value. So you can annotate with [ref] to force the compiler to pass the parameter as a reference.

function DoStuff(const [ref] Info: TInfo): Integer; cdecl; external libname;
David Heffernan
  • 601,492
  • 42
  • 1,072
  • 1,490
  • Thanks for that. "But because TInfo is small, the compiler might choose to pass the structure by value." You have seen this documented somewhere, or did you observe this in the compilation output? –  Dec 02 '16 at 10:11
  • The documentation is pretty unclear. Only the 32 bit Windows compiler's ABI is remotely [documented](http://docwiki.embarcadero.com/RADStudio/en/Program_Control_(Delphi)) by Emba, and then not terribly well. The coverage of `const` arguments is, er, well, incomplete. But yes, records can be pushed by value or by reference, depending on their size. For the code in my answer, without `[ref]`, the two Windows compilers will pass by value. Add another `int` to the struct and the 32 bit compiler passes by reference, but the 64 bit compiler by value. Add another one and both pass by reference. – David Heffernan Dec 02 '16 at 10:20
  • ha that is pretty much exactly what I was trying to find out. Thanks –  Dec 02 '16 at 10:22
  • 1
    It remains to be noted that `const`, in this context, is not very useful anyway, so I would explicitly declare David's example as `function DoStuff(var Info: TInfo)...` or `function DoStuff(Info: PInfo)...`.. – Rudy Velthuis Dec 02 '16 at 11:05
  • @RudyVelthuis The example is not meant to be realistic. Imagine it's a struct that is passed as an IN parameter. And so `const` is appropriate. So, `var` and `PInfo` are not appropriate. – David Heffernan Dec 02 '16 at 11:27
  • When dealing with APIs, it is my experience that `const` is not useful at all. If the struct has to be passed by reference, it suffices to use `var`. – Rudy Velthuis Dec 03 '16 at 11:44
  • 3
    @rudy That tells the caller that the value can be modified. A bad idea. – David Heffernan Dec 03 '16 at 11:46
  • 1
    The parameters give the programmer useful information. – David Heffernan Dec 03 '16 at 18:36
  • In the case of an API, I don't think it matters. If you must pass by reference, use `var` or `out`. The attribute is a bit of an unnecessary kludge, IMO. – Rudy Velthuis Dec 04 '16 at 19:20
0

Another example is the new FreeAndNil procedure declaration in Delphi 10.4 in SysUtils.pas, which now finally ensures that only TObject descendants can be used with FreeAndNil. In previous Delphi versions, you could pass anything to this function, even if it didn't make sense.

superflexible
  • 153
  • 2
  • 9