Tommi Prami 146 Posted March 17 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
Stefan Glienke 2133 Posted March 17 It is briefly explained under Constant Parameters - it enforces the parameter to be passed as a reference. 3 Share this post Link to post
havrlisan 38 Posted March 17 Dalija Prašnikar has a great article on what it's purpose is in FreeAndNil: https://dalijap.blogspot.com/2020/06/magic-behind-freeandnil.html 1 Share this post Link to post
Tommi Prami 146 Posted March 17 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
Hans♫ 81 Posted March 17 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
Tommi Prami 146 Posted March 17 (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 March 17 by Tommi Prami Share this post Link to post
havrlisan 38 Posted March 17 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
Hans♫ 81 Posted March 17 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
Rollo62 573 Posted March 17 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
Hans♫ 81 Posted March 17 (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 March 17 by Hans♫ 1 Share this post Link to post
HeartWare 5 Posted March 17 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. 1 Share this post Link to post
Cristian Peța 115 Posted March 17 (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 March 17 by Cristian Peța 2 1 Share this post Link to post
pmcgee 27 Posted Saturday at 01:25 PM 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
David Heffernan 2433 Posted 19 hours ago 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
dummzeuch 1639 Posted 17 hours ago 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? 1 Share this post Link to post
David Heffernan 2433 Posted 16 hours ago 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
dummzeuch 1639 Posted 16 hours ago (edited) 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 16 hours ago by dummzeuch Share this post Link to post
David Heffernan 2433 Posted 15 hours ago 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
Dalija Prasnikar 1495 Posted 14 hours ago 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. 3 2 Share this post Link to post
Stefan Glienke 2133 Posted 11 hours ago (edited) 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 11 hours ago by Stefan Glienke 2 Share this post Link to post