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 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. |