Jump to content
Tommi Prami

What does [ref] attribute actually dows

Recommended Posts

Hello,

 

Tried to find the documentation of [ref] attribute, famously used in FreeAndNil -implementation lately, but could not find it from Embacdero help.
(FreeAndNil is defined as: procedure FreeAndNil(const [ref] Obj: TObject);)

So could someone point me to the documentation of the attribute ands/or explain what it actually does?

 

-Tee-

Share this post


Link to post

I have been in impression that const actually would do something like that already. So parameter would be passed as reference.  Will juust not allow changin it....

Is there some clear benefit of using [ref],m unless in need of doing something like in  the FreeAndNil iomplementation.

Share this post


Link to post
3 minutes ago, Tommi Prami said:

Is there some clear benefit of using [ref],m unless in need of doing something like in  the FreeAndNil iomplementation.

I think the answer is in this text from the FreeAndNil article linked above:

 

... [ref], which forces the compiler to pass a const parameter as a reference. Without it, the compiler can optimize passing of const parameter depending on the size of the parameter. 

Share this post


Link to post
Posted (edited)
23 minutes ago, Hans♫ said:

I think the answer is in this text from the FreeAndNil article linked above:

 

... [ref], which forces the compiler to pass a const parameter as a reference. Without it, the compiler can optimize passing of const parameter depending on the size of the parameter. 

Tried that with record as parameter, did not see any speedup, const and const [ref] had same performance. 

Winning clearly if it was passed as by value eith const ore var.

I was jsut thinkin that could there be places and code (in my code ba se for example) thjat could benefit from [ref]?

-Tee-

Edited by Tommi Prami

Share this post


Link to post
16 minutes ago, Tommi Prami said:

I was jsut thinkin that could there be places and code (in my code ba se for example) thjat could benefit from [ref]?

Only if you need to access the actual reference.

Share this post


Link to post
50 minutes ago, Tommi Prami said:

Tried that with record as parameter, did not see any speedup, const and const [ref] had same performance. 

Thats because there is no difference. As the text says, with "const" only, the compiler decides the most efficient way. For a record the most efficient way is to pass its reference, so adding [ref] makes no difference.

Share this post


Link to post
3 minutes ago, Hans♫ said:

For a record the most efficient way is to pass its reference, so adding [ref] makes no difference.

Is that always guaranteed?
I would think that the compiler may decide to copy by value for small records.

Share this post


Link to post
Posted (edited)
19 minutes ago, Rollo62 said:

Is that always guaranteed?

Ha, ha, I am sure you know what I mean 😉 I'm no expert in the compilers memory management and optimization. I was trying to explain why it made no difference to add [ref]. 

I guess that if you create a "packed" record that is smaller than a pointer then it will be passed by value.

Edited by Hans♫
  • Like 1

Share this post


Link to post

CONST [ref] is on the surface the same as VAR but it allows a CLASS variable of a descendant to be passed. So where a VAR TObject only allows variables declared as TObject, a CONST [ref] TObject parameter passes a reference (like VAR does) to the instance pointer, but allows all descendants of TObject to be passed in. This eliminates the issue with a typeless VAR to FreeAndNIL also accepting non-classes.

  • Like 1

Share this post


Link to post
Posted (edited)
15 hours ago, Tommi Prami said:

I have been in impression that const actually would do something like that already

With const, if the variable is small enough to pass into a register, it will not be passed always as reference. You need to use [ref] to be sure it is passed as reference. This is the reason to use [ref] for FreeAndNil.

Edited by Cristian Peța
  • Like 2
  • Thanks 1

Share this post


Link to post

One thing I noticed about Const[ref] relates to 'reference shadowing' (maybe there's a better term).

 

If you call a function/procedure that takes a const string, the function uses a new reference to the string.

With const[ref] it uses the exact existing reference.

 

 

 

{$APPTYPE CONSOLE}
program Project1;
uses
  system.SysUtils,
  System.Generics.Collections;

type
  pr = TPair<integer,integer>;

procedure call_i1 (     const x:integer);  begin  writeln( integer(@x) );  end;
procedure call_i2 (const[ref] x:integer);  begin  writeln( integer(@x) );  end;
procedure call_c1 (     const x:TObject);  begin  writeln( integer(@x) );  end;
procedure call_c2 (const[ref] x:TObject);  begin  writeln( integer(@x) );  end;
procedure call_s1 (     const x:string);   begin  writeln( integer(@x) );  end;
procedure call_s2 (const[ref] x:string);   begin  writeln( integer(@x) );  end;
procedure call_p1 (     const x:pr);       begin  writeln( integer(@x) );  end;
procedure call_p2 (const[ref] x:pr);       begin  writeln( integer(@x) );  end;

begin
  var i : integer;
  var o : TObject;
  var p : pr;
  var s : string;

  writeln( integer(@i) ); call_i2(i); call_i1(i); writeln;
  writeln( integer(@o) ); call_c2(o); call_c1(o); writeln;
  writeln( integer(@s) ); call_s2(s); call_s1(s); writeln;
  writeln( integer(@p) ); call_p2(p); call_p1(p);

  readln;
end.

For TPair, the const[ref] makes no difference ... but for string, integer, and Class, it uses the address of the original value or reference.

 

Quote

int   11533168
int   11533168
int   11533128

 

class 11533164
class 11533164
class 11533128

 

str   11533152
str   11533152
str   11533128

 

tpair 11533156
tpair 11533156
tpair 11533156

 

Share this post


Link to post

Is there any known use case other than the one demonstrated by FreeAndNil, namely to allow modification of a const param?

Share this post


Link to post
2 hours ago, David Heffernan said:

Is there any known use case other than the one demonstrated by FreeAndNil, namely to allow modification of a const param?

Maybe if you want to use ASM to access the parameter?

  • Like 1

Share this post


Link to post
3 minutes ago, dummzeuch said:

Maybe if you want to use ASM to access the parameter?

Why would [ref] be needed to use asm? 

Share this post


Link to post
54 minutes ago, David Heffernan said:

Why would [ref] be needed to use asm? 

If you pass a const parameter which you want to reference by its address in asm code, you need to make sure that it actually is passed as a reference and not in any other form.

Edited by dummzeuch

Share this post


Link to post

Whether or not you want to use asm is not relevant. It's what you do with it that matters. 

 

I mean, exactly what you said above would apply equally if you wanted to write the code in pascal. 

Share this post


Link to post
5 hours ago, David Heffernan said:

Is there any known use case other than the one demonstrated by FreeAndNil, namely to allow modification of a const param?

I think that original need to introducing [ref] was the need to force passing value parameters as references so they would match some cross platform API. I don't remember whether that was merely a difference between 32-bit and 64-bit Windows platforms, or there were other OS involved. I also don't remember whether C++ Builder support also had something to do with it. AFAIK, Allen Bauer explained this somewhere. I am not sure if this was only on his blog or it was also mentioned on old forums.

 

New FreeAndNil implementation came years later and it merely used the feature that was introduced for other reasons.

  • Like 3
  • Thanks 2

Share this post


Link to post
On 5/10/2025 at 3:25 PM, pmcgee said:

If you call a function/procedure that takes a const string, the function uses a new reference to the string.

Yes, no surprise - because const[ref] forces a reference type variable to be passed by reference - build version three of your routines that have their parameter as var, and you will see.

 

Also, your reasoning about what you see is mistaken - if you retrieve the address of a parameter or variable that resides in a register, the compiler will reserve stack space for it to retrieve the address of it.

In the case of passing a const string as first and only parameter that one will be passed in eax on 32bit windows, or rcx in 64bit windows - calling @ on that parameter cannot give an address if that parameter stays in the register, hence the compiler generates code to reserve stack space, and puts the value there and retrieves that address.

Edited by Stefan Glienke
  • Like 2

Share this post


Link to post

Create an account or sign in to comment

You need to be a member in order to leave a comment

Create an account

Sign up for a new account in our community. It's easy!

Register a new account

Sign in

Already have an account? Sign in here.

Sign In Now

×