Delphi has had a more type safe FreeAndNil or a while now, but in order to do so it lies to you
Posted by jpluimers on 2024/06/26
During my year+ of cancer treatments, Embarcadero did a tiny thing that makes [Wayback/Archive]FreeAndNil safer to use. In order to do so, the method now lies to you by taking a const [ref] parameter which technically it is not allowed to change, but the internal hackery allows it to. Dalija Prasnikar explained it in 2020: [Wayback/Archive] Magic behind FreeAndNil.
The new signature is this:
procedure FreeAndNil(const [ref] Obj: TObject); inline;
and the implementation this (all details explained in the above post).
procedure FreeAndNil(const [ref] Obj: TObject); var Temp: TObject; begin Temp := Obj; TObject(Pointer(@Obj)^) := nil; Temp.Free; end;
This means that if you are on recent versions of Delphi (a lot of shops don’t, as they got upgrade shy since over the past 10+ years all gold Delphi releases of the last 10+ years come with major issues only to be solved months later or not at all) breaking code on the compiler, RTL or IDE level.
I still dislike using FreeAndNil as the methods does two things at once which from a conceptual point of view is bad: it causes side effects.
That means the other reasons I mention in Another case against FreeAndNil still stand, in addition to neither FreeAndNil nor if Assigned(reference) then DoSomeThingWith(reference) are being thread-safe like for instance Dalija mentions in [Wayback/Archive] FreeAndNil Debate: Thread Safety (via [Wayback/Archive] Dalija Prasnikar on Twitter: “I mentioned using interfaces for achieving thread safety in yesterday’s FreeAndNil debate. But, the way I said it, it came out wrong and it can lead to wrong conclusions: Here is the full story: FreeAndNil Debate: Thread Safety”).
It was cool to see this 2011 post being reposted a week before the webinar: [Wayback/Archive] On Not Using FreeAndNil – Delphi-losophy. It does not mention threading at all, which confirms my observation that few Delphi programmers back then really were into multi-threading.
Boy the days have changed, so I was not surprised by [Wayback/Archive] Dalija Prasnikar on Twitter: “@JimMcKeeth Solution for another timeline: Bring ARC compiler on all platforms, rewrite RTL, VCL, and FMX so they don’t need DisposeOf, and voila there is no more FreeAndNil debate because there is no more FreeAndNil 😎”.
Quite a bit of Q&A on the webinar has been added to [Wayback/Archive] FreeAndNil() – Delphi Developer Debate.
A good introduction thread is at [Wayback/Archive] Thread by @dalijap on Thread Reader App
FreeAndNil()andAssigned()debate is coming up soon blogs.embarcadero.com/freeandnil-del…This may seem like simple topic, but in order to discuss when and whether one should use FreeAndNil() and Assigned(), we need to understand related, more complex processes happening in our code.
…
Via: [Wayback/Archive] Dalija Prasnikar on Twitter: “@jpluimers Since Delphi 10.4 Sydney, FreeAndNil signature has been changed and interface reference can no longer be passed by mistake. “
Edit 20240711
Related blog post: Another case against FreeAndNil (which also provides a generic and type-safe class procedure FreeAndNil<T: class>(var Value: T) implementation in a unit called ObjectHelperUnit that works as of Delphi 2009 in stead of as of Delphi 10.4)
Free Pascal implementation by Thaddy: [Wayback/Archive] Lazarus » Forum » Programming » General » FreeAndNil revisited, but now properly. with a related thread at [Wayback/Archive] Lazarus » Forum » Programming » General » FreeAndNil.
--jeroen
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| unit ObjectHelperUnit; | |
| interface | |
| type | |
| TObjectHelper = record | |
| class function Cast<T: class>(const aValue: TObject): T; static; | |
| class procedure FreeAndNil<T: class>(var Value: T); static; | |
| end; | |
| implementation | |
| uses | |
| System.SysConst, | |
| System.SysUtils; | |
| class function TObjectHelper.Cast<T>(const aValue: TObject): T; | |
| var | |
| lException: Exception; | |
| begin | |
| if Assigned(aValue) then | |
| begin | |
| if aValue is T then | |
| Result := T(aValue) | |
| else | |
| begin | |
| lException := EInvalidCast.CreateFmt('%s; actual type %s but expected %s.', | |
| [SInvalidCast, aValue.QualifiedClassName, T.QualifiedClassName]); | |
| raise lException; | |
| end; | |
| end | |
| else | |
| Result := nil; | |
| end; | |
| class procedure TObjectHelper.FreeAndNil<T>(var Value: T); | |
| begin | |
| System.SysUtils.FreeAndNil(Value); | |
| end; | |
| end. |






thaddy said
Implemented it. In freepascal…
https://forum.lazarus.freepascal.org/index.php/topic,67744.msg522087.html#msg522087
jpluimers said
Thanks for implementing this in FreePascal. Will add your information to the blog post.
Delphi indeed does not allow that kind of solution, but I developed a class helper some 10 years ago and published a few later as https://wiert.me/2017/12/21/another-case-against-freeandnil/ with the ObjectHelperUnit at https://gist.github.com/jpluimers/31a036b7c91bc121c422fcb1a0adbd39 that works in a similar way (but defers the actual freeing to the
System.SysUtils.FreeAndNilmethod.