As a Delphi MVP, I was surveyed on my stance of the use of
FreeAndNil. In that questionnaire was included a question about the use of
Assigned(). Really? Is that debated as well? I couldn't find anything on the internet debating this except for an old discussion on StackOverflow. I use this function frequently and as I looked more deeply at what it does, I'm even more confident of its use.
Basically what the
System.Assigned() function does is "Tests for a nil (unassigned) pointer or procedural variable." In other words, the following statement makes sure the variable
P is not nil:
if Assigned(P) then ...
On the surface, that seems equivalent to just simply writing:
if P <> nil then ...
For regular object variables, that is equivalent but this function also works on procedural variables. If
P is a procedural variable, you'd have to write this instead:
if @P <> nil then ...
Assigned(), both of those scenarios are automatically covered.
My most frequent use of
Assigned is when calling event handlers from a class. For example, let's say I have a class that performs a task and it provides events for when it starts, stops, and to report its progress. The calling program or class can hook into those events to log the activity or display status on the screen to the user. It might look like this:
type TMyTaskClass = class private FOnStartTask: TNotifyEvent; FOnEndTask: TNotifyEvent; FOnNotifyProgress: TGetStrProc; public property OnNotifyProgress: TGetStrProc read FOnNotifyProgress write FOnNotifyProgress; property OnStartTask: TNotifyEvent read FOnStartTask write FOnStartTask; property OnEndTask: TNotifyEvent read FOnEndTask write FOnEndTask; end;
The class would have additional methods to do the work for which this class was designed and somewhere in those methods the event handlers would need to be called. But hooking into the events is optional--this class could be used, for example, from a unit test that completely ignores the events. So each time the event handlers are called, they need to be checked to see if they're assigned. Doing that every time you need to call an event is messy so I put those checks into "Do" methods, typically in a "protected" section of the class:
protected procedure DoOnNotifyProgress(const S: string); procedure DoOnStartTask(Sender: TObject); procedure DoOnEndTask(Sender: TObject);
The bodies of these procedures look like this:
procedure TMyClass.DoOnNotifyProgress(const S: string); begin if Assigned(FOnNotifyProgress) then FOnNotifyProgress('Progress: ' + S); end; procedure TMyClass.DoOnEndTask(Sender: TObject); begin if Assigned(FOnEndTask) then FOnEndTask(Self); end; procedure TMyClass.DoOnStartTask(Sender: TObject); begin if Assigned(FOnStartTask) then FOnStartTask(Self); end;
The call to
Assigned() in these procedures checks to see if the event handlers are hooked up and if so, calls them. The main body of the class can now simply call these "Do" procedures whenever it needs to trigger event handlers.
Another common use is when parsing XML or JSON data. For example, the
System.JSON.TJSONValue.GetValue function returns an object parsed from a JSON string but if the
Path parameter was not found, the result is nil. Checking for this is key when dealing with public REST APIs that may return varying results.
Other places where I use the
Assigned() test is in the destructor of a class that created objects in the constructor and I want to make sure they were actually created before attempting to free their memory. (Of course, if you adhere to Dependency Injection principles, strongly promoted by Nick Hodges, your classes won't typically create their own objects--a practice I should adopt more rigidly.)
An aesthetic advantage to using
Assigned() over explicitly checking the value against nil is if there are multiple clauses in an
if statement, you don't need to use as many parenthesis--a minor point but keeps the code just a little cleaner and easier to read.
One important thing to remember is that
Assigned() does not validate a pointer, it simply checks to see if the pointer has some value indicating it was purposefully assigned at some point with a valid address; the object to which it points could've been freed--an argument for promoting the use of FreeAndNil.
Overall, I believe that
Assigned() is very useful in many cases--I doubt many will disagree.
You are missing an important…
You are missing an important point of what Assigned() does for event handlers: It only checks the code part of a method pointer (see the TMethod record declaration), not the data part.
Add new comment