Quantcast
Channel: Delphi – The Wiert Corner – irregular stream of stuff
Viewing all articles
Browse latest Browse all 1446

Delphi has had a more type safe FreeAndNil or a while now, but in order to do so it lies to you

$
0
0

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() and Assigned() 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.

Viewing all articles
Browse latest Browse all 1446

Trending Articles