Amazon.com Widgets More on FreeAndNil

More on FreeAndNil

By Nick at January 02, 2012 05:03
Filed Under: Software Development, Delphi

I love a good, testy comment section in a blog post.  Winking smile  The discussion in the comment section of my FreeAndNil post has been interesting and lively.  In addition, the thread in non-technical continues apace, with new threads springing up!  Along the way, a couple of interesting points were made that I’d like to highlight here because I think they are germane.

  • First, I can sum up the article as follows: “Don’t use FreeAndNil.  If you feel the need to use FreeAndNil, then your code almost certainly needs to be refactored to limit the scope of your references.”.    People arguing for it’s use are, in my mind, simply saying “I don’t know how to or don’t care to control the scope of my pointers” 
  • Second, I want to stress again that I totally get that sometimes you have to use FreeAndNil. Sometimes you maintain old code that played fast and loose with pointer scope, and didn’t contain things like we now know you should.  I get that.  But those situations should cause you shame and embarrassment, and should motivate you to refactor your code to control references and make the need for FreeAndNil go away.  The reason that I totally get this is that I manage such a codebase.  The point isn’t about maintaining legacy code, it’s about how to write new code the right way.  And if you are writing new code while feeling the need to FreeAndNil stuff, then you aren’t doing it right, quite frankly.
  • Jolyon Smith wrote the following in the comments: “Surely you must also admonish everyone to write code that never requires the use of if Assigned(someReference) then…”  Well, yes, I suppose that is exactly correct in most cases, unless you are doing lazy initialization, which I wouldn't recommend using anyway.  If you are using Dependency Injection -- and you should be -- there is never a reason to be worried about your references not being assigned. 
  • John Jacobson writes: “Reference-counted interfaces are what you should be using anyway, keeping your actual class implementations private and hidden in the implementation section of their unit.”  He’s absolutely correct. Ultimately, you should be coding against abstractions, not implementations.  If you are doing that – and of course you should be in Delphi via reference-counted interfaces – then you shouldn’t be freeing anything other than local, non-volatile variables, and you should never need to FreeAndNil those.

By now many of you all are probably saying “This guy is a nut!  Get over the FreeAndNil thing already!”  Well, okay, I agree I’ve beaten this drum quite a bit.  And I agree that I’m pretty much a nut. But I really think that it represents a critical point that we all need to understand in order to move forward:  Code needs to be under control.  Good development dictates that we limit the scope of references.  And finally, out of control references are the cause of many, many bugs, and are the cause of 100% of access violations.  The use of FreeAndNil is a blatant symptom of this problem.

Here’s the bottom line, and I’ll be blunt: If you are arguing in favor of using FreeAndNil, what I really hear you saying is “I learned to code in 1991 and haven’t learned a thing since.” 

Okay, that’s a little harsh.  I’ll put it a bit softer:  Worrying about pointers and references is, well, an old-fashioned way of thinking.  There are ways to code so that worrying about whether a pointer is valid or not is no longer something you have to worry about.  This way of coding is more productive, cleaner, and more effective.  It produces high-quality, testable code.  

Doesn’t that sound enticing and intriguing?  Why wouldn’t you want to learn more?

Comments (72) -

1/2/2012 5:58:53 AM #

Clint --

Please feel free to repost your comment without the childish name-calling.

Nick Hodges United States |

1/2/2012 7:10:47 AM #

You argue that if you maintain tight control the scope of your pointers, you don't need to worry about accessing after free. That argument is clear and nobody appears to disagree with it.

What you have not made a case for is your conclusion that using FreeAndNil means that you do not have tight control over the scope of your pointers. You have fallen for what I call a *false dichotomy*.

It may be true that poor programmers and poor codebases often contain both badly managed pointer scope and lots of FreeAndNil. That proves nothing. It is perfectly possible to have tight control over the scope of your pointers *and* use FreeAndNil.

As a though experiment, imagine replacing all uses of Free, in your pristine well-formed code, with FreeAndNil. Would that change the scope of your pointers?

Your fundamental point regarding managing lifetime and scope is excellent. But it seems to me that you are diluting the message with an orthogonal issue.

David Heffernan United Kingdom |

1/2/2012 8:48:34 AM #

>>What you have not made a case for is your conclusion that using FreeAndNil means that you do not have tight control over the scope of your pointers. You have fallen for what I call a *false dichotomy*.<<

No, in this case, you've created what is called a "straw man argument". You' accused me of making a conclusion I have not made.  I've been very careful to say something like "If you *feel the need* to use FreeAndNil, then you have out of control pointers".  Note the (added) emphasis on "feel the need".  I've never made the argument you attempt to refute.  It's obvious that FreeAndNil can functionally replace Free.

In the original post, I made the case that the indiscriminate use of FreeAndNil is obfuscating, making the distinction between FreeAndNil and Free meaningless.  It also sends an unclear message, causing people to say "Hey, what the heck, why is this FreeAndNil and not just Free".  Code should be precise and say what needs to be said and nothing more.

Nick Hodges United States |

1/2/2012 7:48:50 AM #

First off, I find this kind of persistent dogmatism hardly bearable. Doesn't help with a well-balanced discussion if you ask me. It might also explain the quality of comments you're getting: the people capable of making elaborate counter-arguments probably shaked their heads and moved on.

(Dear commenters, no, I didn't read your comments, yes, it's a rhetoric hyperbole. Please don't feel offended.)

Secondly, while I don't have anything fundamentally significant to say about FreeAndNil(), I just grepped my code base and found quite a number of references to it. You probably wouldn't accept the first thing I hit because it was an array helper routine which helps me to get by without using an TObjectList&lt;&gt; (it happens that I don't want to pull in Generics.Collections), but the next one appears unconditionally legitimate to me:
<code>function TRelocatableWithRelocator.GetAsRelocator: TRelocator;
begin
  if FRelocator = nil then
    try
      FRelocator := TRelocator.Create (GetDataKind);
      WriteToRelocator (FRelocator);
    except
      FreeAndNil (FRelocator);
      raise;
    end;
  Result := FRelocator;
end;</code>

Never mind what a relocator is at this point. The pattern can be generalized. If you have a function which creates an object, operates on it and then passes it to the caller, you'll always want to use a try/except construction as above to free the object in case of failure. Combine that with "lazy evaluation", i.e. having an object property which caches the result of some function, and you have a use case for FreeAndNil().

Looking forward to see how you rip that one apart.

Moritz Beutel Germany |

1/2/2012 8:58:31 AM #

Moritz --

I'll "rip it apart" by saying that code is crying out to be refactored into the Factory pattern, or better yet, to get TRelocator via some form of dependency injection.

Nick Hodges United States |

1/2/2012 10:39:05 AM #

And that contradicts my use of FreeAndNil(), how? It doesn't matter where I got my TRelocator instance from. As long as obtaining the instance and operating on it are two different steps, my code will essentially have to look like it does now, with both try-except and FreeAndNil().

Of course the FreeAndNil() will be substituted with "FRelocator := nil" if I use a garbage collector or if FRelocator is an interface reference. Obviously, if you restrict yourself to coding against interfaces and never touch object references at all, there will be no need for FreeAndNil() neither here nor anywhere else. But that's not the point.

Moritz Beutel Germany |

1/2/2012 1:02:22 PM #

Why is the call to create *inside* the try block?  If you leave it outside the try call, as you should, you've no need to call FreeAndNil.

Nick Hodges United States |

1/2/2012 1:45:47 PM #

Having the call inside may look unconventional but is okay in this case. It does make a difference if FRelocator cannot be expected be nil (if it were a local variable), but as a field it will be initialized to nil. A caching mechanism has to rely on that fact, and I placed the call inside in order to manifest that expectation. But this is without consequence for FreeAndNil(); if WriteToRelocator() fails such that the obtainment of the object has to be considered unsuccessful, you'll have to do a complete rollback, i.e. you will still need to release the object and reset the reference, and this is most comfortably done at once with FreeAndNil().

(Why is the font size of nested comments constantly increasing? This feels like I'm unintentionally shouting all the time. Perhaps I should start writing with caps lock to round it out...)

Moritz Beutel Germany |

1/3/2012 3:28:37 AM #

I don't know why the nested comments are getting bigger.  I'll look into it.

Nick Hodges United States |

1/3/2012 4:07:25 AM #

There's probably a superfluous FreeAndNil() call in the forum code.

Jan Derk Netherlands |

1/2/2012 12:03:17 PM #

Doesn't that just move the same code somewhere else?

David Heffernan United Kingdom |

1/2/2012 9:06:25 AM #

Why are you calling create? You should be letting your DI container do that.

Tapper United States |

1/2/2012 1:03:41 PM #

Exactly.  Creating objects is outside the scope of the expressed purpose of any class unless the expressed purpose of a class is to create things --  like a factory.

Nick Hodges United States |

1/2/2012 1:51:04 PM #

I see. I could start grepping my code base for direct constructor calls now, but I guess I'd better give in at this point Smile I cannot argue against dogma.

Moritz Beutel Germany |

1/2/2012 3:28:43 PM #

One of the things that I find interesting about all this is the ire that I've engendered from some quarters.

Labeling "effective argument" as "dogma" is not very compelling.

If "dogma" is defined as "putting forth sound development ideas", then yes, I'm totally in favor of being dogmatic.

Nick Hodges United States |

1/2/2012 5:41:55 PM #

Effective argument isn't dogma. Effective argument would be welcome here.

David Heffernan United Kingdom |

1/3/2012 3:29:55 AM #

David -

Hey, apparently you don't recognize effective arguments.  

You don't have to agree with what I say, but it's the height of fallacious argumenting to simply dismiss valid arguments with which you don't agree as "dogma".  

Nick Hodges United States |

1/3/2012 5:10:36 AM #

Stating that your arguments are valid does not make them so. I simply don't agree that exclusive use of FreeAndNil implies that your code is of poorer quality than the use patterns you advocate. FreeAndNil is not the problem. The problem is poor coding. That's what you are trying to say but somehow FAN is getting mixed up.

David Heffernan United Kingdom |

1/17/2012 11:15:58 AM #

And the "try" should be AFTER the creation of the object, not before:

var result : TFoo = TFoo.Create();
try
   result.do;
except
   FreeAndPossiblyEvenNil(result);
   raise;
end

else you might try and free foo before it has been created. An error in construction is very different than an error in operation.

Richard C Haven United States |

1/2/2012 8:03:48 AM #

I have found 3 rules for this topic and i think if you follow these rules your code is just fine.

Rule 1:
Don't use FreeAndNil() where .Free is sufficient.

procedure TMyClass.Destroy;
begin
  // misused FreeAndNil()
  FreeAndNil(FInnerObject); // livetime of "FInnerObject" ends here
  inherrited;
end;  // Scope of FInnerObject ends here

Rule 2:
Use FreeAndNil() if the livetime of the object is shorter than the scope
and there is a chance that the object pointer could (accidently) accessed again.

procedure TForm1.ButtonCloseForm2Click(Sender:TObject);
begin
  Form2.Free;
  // Form2 is a global variable
  // so it is possible to access Form2 later on because the scope is also global
  // FreeAndNil(Form2) should be used instead
end;

Rule 3:
Design your code to avoid using FreeAndNil() where possible.
Prefer rule 3 over rule 2 and use dependency injection.
Nick wrote: “Don’t use FreeAndNil“.
I would say: "Try to avoid FreeAndNil wherever you can".

sx2008 Germany |

1/2/2012 9:00:44 AM #

sx2008 --

I'd argue that your Rule #2 is always unnecessary and should be avoided entirely.  Global variables should be avoided at all costs.

And again, a careful reading of my writings will show I've never said "Don't use it", I've said "Don't use it in new code".

Nick Hodges United States |

1/2/2012 10:10:57 AM #

I don't like rule #2. My rule #2 would be: ensure that an object remains alive as long as it is publicly accessible. On first access, it should either be alive already (e.g. initialized in a constructor) or it should be lazy initialized (e.g. by a property accessor). Then it should not be freed before the containing object is freed.

FWIW, my rule #1 would be: limit the scope of pointers/references as much as possible.

My rule #3: avoid re-using fields. They should be initialized, kept alive as long as necessary - but e.g. clearing them is OK -  and then terminated (usually in a destructor) and not be re-used.

E.g. if you need it only in one routine, create it and free it in that routine (using try-finally). If you need it in a number of routines, then create a new routine in which you create it, pass it to those routines (IOW, NOT as field of your object, but as parameter) and then free it. If you need it for the lifetime of the object, see rule #2.

Rudy Velthuis Germany |

1/2/2012 10:16:42 AM #

I'd say that the lifetime of an object should never be shorter than the (public) scope. If it is still publicly accessible, it should remain alive.

Rudy Velthuis Germany |

1/2/2012 7:24:18 PM #

That rule would be great but unfortunately the language doesn't allow scoping of local variables to be any shorter than a method. Big weakness in the language that all other comparable languages have long since corrected.

David Heffernan United Kingdom |

1/3/2012 3:30:41 AM #

Limit your method sizes and the problem goes away. One could argue that if you feel the need to have a variable smaller than the scope of a method, then you should refactor.

Nick Hodges United States |

1/3/2012 5:07:29 AM #

Mostly that's right. But there are times when you follow that to its logical conclusion and your methods become too small and they become dislocated from each other. So the ability to limit scope of local variables to blocks within a method would be a definite benefit.

David Heffernan United Kingdom |

1/4/2012 7:42:46 AM #

I have yet to see "too small methods". Mostly they are too big. You just need a good code explorer (like MMX) to help you navigate the methods as necessary (and refactor quickly whenever necessary, MMX again)

Jouni Aro Finland |

1/19/2012 10:39:26 PM #

use nested procedures or maybe anonymous ones

Arioch Russia |

1/2/2012 9:35:25 AM #

“If your code requires you to use FreeAndNil to reveal and easily find bugs, then your design is wrong.  Good, clean code never feels the need to worry about errant pointers.”
That was your summary from the first post. That refutes straw man.

David Heffernan United Kingdom |

1/2/2012 9:50:11 AM #

No, sorry, it doesn't "refute [the] strawman", something one can't really do.  What you quoted solidifies and advances my argument quite nicely.


Nick Hodges United States |

1/2/2012 10:39:38 AM #

OK, I give up. For the life of me I cannot see why you believe that using FreeAndNil results in code with more defects. And if you don't believe that (I'm not sure I can discern what you believe anymore) then I can't see why you are so obsessed by whether or not a variable is set to nil.

David Heffernan United Kingdom |

1/2/2012 1:10:54 PM #

David --

"OK, I give up. For the life of me I cannot see why you believe that using FreeAndNil results in code with more defects."  

I can't see why I'd believe that either, given that I don't believe it, and have never argued such a point.

I do believe that the blanket use of FreeAndNil can *hide* problems with code, and can let bad design be perpetuated.  As I noted in the original article, if you are using it in the "It'll cover up AV's" mode, then you have to use it correctly in every case in many places throughout a codebase.  I myself prefer an approach where I don't have to be right in 500 different places and only have to be right in one place.

"And if you don't believe that (I'm not sure I can discern what you believe anymore) then I can't see why you are so obsessed by whether or not a variable is set to nil."

LOL -- I think it's funny that you are accusing me of being obsessed by whether or not a variable is set to nil when advocating that you shouldn't ever care whether a reference is currently nil or not.   *I'm* not the one calling for the nil-ing of variables with reckless abandon. Wink

Nick Hodges United States |

1/2/2012 7:30:08 PM #

> I do believe that the blanket use of FreeAndNil can *hide* problems with code, and can let bad design be perpetuated.

The problem then is the bad design. That's what should be attacked. You are conflating two orthogonal issues. Correlation does not imply causality. It is possible to write bad code without FreeAndNil and write good code with it.

> If you are using it in the "It'll cover up AV's" mode

It doesn't ever cover up AVs. Using FreeAndNil may bring non-manifesting errors to light. It never covers things up. Either you don't fully understand why some people use it, or your terminology was sloppy. I suspect the latter.

> then you have to use it correctly in every case in many places throughout a codebase.

Why? If you are using it as a debugging tool and use it 90% of the time then it will have 90% of the impact. That's better than 0% of the impact. You argument there makes no sense. It's like saying that partial test coverage is no better than no test coverage. Comprehensive coverage is best, but 90% coverage is better than none.

> I'm not the one calling for the nil-ing of variables with reckless abandon.

And neither am I. I can't see anyone doing that. I'm just trying to point out the flaws in your logic.

David Heffernan United Kingdom |

1/3/2012 4:09:38 AM #

"And neither am I. I can't see anyone doing that."

Many people advocate using FreeAndNil in every case.

"I'm just trying to point out the flaws in your logic."

I get that, but you are doing it by accusing me of making arguments I'm not making. For instance, you said:

"The problem then is the bad design. That's what should be attacked. "

which, of course, is exactly what I've been doing all along.

Nick Hodges United States |

1/3/2012 5:13:27 AM #

> "The problem then is the bad design. That's what should be attacked. "

> which, of course, is exactly what I've been doing all along.

No, you've been attacking the use of FAN.

>  If you are arguing in favor of using FreeAndNil, what I really hear you saying is “I learned to code in 1991 and haven’t learned a thing since.”

David Heffernan United Kingdom |

1/3/2012 5:38:36 AM #

David --

"No, you've been attacking the use of FAN."

Seriously, you need to read more carefully. Y

Nick Hodges United States |

1/3/2012 7:26:59 AM #

Explain how to read this more carefully:

If you are arguing in favor of using FreeAndNil, what I really hear you saying is “I learned to code in 1991 and haven’t learned a thing since.”

David Heffernan United Kingdom |

1/2/2012 10:43:51 AM #

If you wanted to expend some energy on something useful then you could start a campaign for an enhancement to the language  to make it possible to limit the scope of local variables. That's a huge weakness with Delphi when compared with C++, Java, C#. That's the main issue you are trying to make and you'd do far better in my view to stick to the nub of the matter and avoid the religion.

David Heffernan United Kingdom |

1/2/2012 10:50:22 AM #

I think that particular Delphi language enhancement is expected to coincide with hell freezing over Smile

Moritz Beutel Germany |

1/2/2012 11:34:03 AM #

According to a popular essay on this subject, hell is exothermic and will never freeze.

Barry Staes Netherlands |

1/16/2012 6:23:57 PM #

According to Dante, the centre of Hell _is_ frozen: "This is the deepest level of hell, where the fallen angel Satan himself resides. His wings flap eternally, producing chilling cold winds that freeze the thick ice found in Cocytus. ... Sinners here are frozen deep in the ice, faces out, eyes and mouths frozen shut. ..."

When should I start looking for limited scope local variables?

Roy Trubshaw United Kingdom |

1/2/2012 1:13:36 PM #

"If you wanted to expend some energy on something useful then you could start a campaign for an enhancement to the language  to make it possible to limit the scope of local variables."

I'm of two minds about that, but both minds recognize that you currently easily can and certainly should limit the scope of local variables by writing methods that don't need variables with a wide scope.  If a method needs a variables scope to be larger than it's usage (i.e., for example, using the same variable twice for different things), then refactoring is in order.

Nick Hodges United States |

1/2/2012 3:56:14 PM #

I saw a great quote few weeks ago, and I wish I could find it again now, along the lines of, "We've all heard, and had explained to us, how testing can never reveal the absence of bugs, only the presence of bugs.  And we dutifully repeat the mantra, and then we all go out and try to find newer and better methods of testing, as if that will somehow help us have less bugs!"

I think that really sums up my feelings towards the concept of "high-quality, testable code" better than anything I could think of to try to express it.  There's no better way to arrive at a bad conclusion than by beginning from a false premise.

Mason Wheeler United States |

1/3/2012 9:32:18 AM #

Found it.  It was from Dijkstra:

<blockquote>It is now two decades since it was pointed out that program testing may convincingly demonstrate the presence of bugs, but can never demonstrate their absence. After quoting this well-publicized remark devoutly, the software engineer returns to the order of the day and continues to refine his testing strategies, just like the alchemist of yore, who continued to refine his chrysocosmic purifications.</blockquote>

Context: www.cs.utexas.edu/.../EWD1036.html

Mason Wheeler United States |

1/4/2012 8:44:37 AM #

Thanks Mason! There was, after all, one pearl (the complete speech of EWD) hidden in this subject as well Smile

Jouni Aro Finland |

1/5/2012 3:54:46 AM #

...and apparently this blog software doesn't support the blockquote tag. Frown

Mason Wheeler United States |

1/2/2012 5:57:51 PM #

"Sometimes you maintain old code that played fast and loose with pointer scope, and didn’t contain things like we now know you should.  I get that.  But those situations should cause you shame and embarrassment, and should motivate you to refactor your code .. "

I remember you saying quite opposite things in nontechnical when you were Codegear manager. For example, when community asked why Codegear still use old and buggy .Net and J# code in IDE.

Serg Russia |

1/2/2012 8:18:25 PM #

+1

Eric France |

1/3/2012 4:11:38 AM #

I don't remember saying "the opposite" at all.  If you have a link to back up your spurious claim, I'll be stunned.

Nick Hodges United States |

1/2/2012 8:18:06 PM #

Dependency Injection turning into a new Hammer?

DI just like FreeAndNil, is just a *tool*, never, ever lose that perspective, or you'll just end up into the realm of dogmatism/bigotry.

Eric France |

1/3/2012 4:12:11 AM #

I completely agree -- DI is just a tool, and a very good one.  It doesn't solve every problem, it just solves some problems very well.

I've noted over the years that cool new tools are often accused of being "hammers" and "dogmatism/bigotry" before being accepted as the standard way of doing business.  OOP comes to mind as an analogous situation.

Nick Hodges United States |

1/2/2012 9:25:09 PM #

I was trying to find a reason to get riled up about the pointlessness of this post, but I realized it was futile somewhere between “People arguing for it’s use are, in my mind, simply saying “I don’t know how to or don’t care to control the scope of my pointers” and "Second, I want to stress again that I totally get that sometimes you have to use FreeAndNil."

Lars Fosdal Norway |

1/2/2012 9:36:44 PM #

You asked for it:
I learned to code in 1991 and haven't learned a thing since.

Thomas Mueller Germany |

1/19/2012 10:46:50 PM #

Som u never use FreeAndNil, do you ?

<i>for it appeared in 1999, so u just had no chance to learn it</i>

Arioch Russia |

1/2/2012 10:25:38 PM #

If learned something new: The latest hype is SADO = (Software As a DOgma)

Peter Müller-Mannhardt Germany |

1/3/2012 5:36:44 AM #

Peter: Your definition of "dogma" appears to be "Beliefs that are strongly held that I don't agree with".

Did I get that right?

Nick Hodges United States |

1/3/2012 12:52:06 AM #

This kind of post must have examples. If you advocate for an use or another, you should post examples of. When you find you can't post all the situations, then, I think, you will understand...

EMB |

1/3/2012 1:52:46 AM #

I like FreeAndNil and I use it because I want to.  I prefer getting an A/V at 00000000 instead of some random address if, for some reason, the pointer IS accessed after being freed.  That way I know I'm looking for a nil-ed pointer and know this is not some random OS crash or A/V caused by the guts of the object being referenced...  For something as fundamental (and often done) as freeing an object, I prefer to keep a single consistent thing going, thus using FreeAndNil everywhere - to me it has nothing to do with testing a pointer later - it is strictly to point me in the right direction during QA/debugging.  Other than a couple of extra clock cycles, there are no drawbacks that I've ever seen...

Ryan McGinty United States |

1/3/2012 7:25:08 AM #

For that case, why not just *not* use FreeAndNil and test with FastMM's FullDebugMode?  Then when you access a freed object you can get all sorts of valuable (and some less-valuable) debug info from it, particularly if you try to call a virtual method on the freed object.

Mason Wheeler United States |

1/4/2012 7:54:15 AM #

While I would love to say "I always release bug free code" that is FAR from accurate, so it comes in handy in the field too when I get a madExcept report for an AV Smile  I've never looked at FullDebugMode, but I will definitely check it out.

Ryan McGinty United States |

1/3/2012 2:12:38 AM #

I recently got bit by my liberal use of FreeAndNil.  I converted the public interface to one of my often used utility classes to use interfaces.  The problem is that this will compile:

var
  x: IMyHelper;
begin
  x := GetMyHelper;
  ...
  FreeAndNil(x);
end;

I had to do careful searching all through my code to avoid runtime errors.

Troy Wolbrink United States |

1/3/2012 2:59:55 AM #

Saying "we don't need destructor with variable zeroing after" we must say "we don't need to newly allocated memory to be zeroed".
So why need to call Free - maybe calling Destroy would be better memory control practice?

While I agree on code relying on some external factors smells bad. But it is not about tight memory control practices, it is about good coding and debugging practices.
I have I convention: no references to destroyed objects. And I can see in debugger when ever watched object was already destroyed. The only bad side effect I see is double destruction hide without raising any exceptions.

Alil Adamov Russia |

1/4/2012 7:56:27 AM #

I do think that this entire discussion (which is YEARS old at this point) is like arguing over how to hold the brush when we all could just be painting the picture with our own style ;)

Ryan McGinty United States |

1/7/2012 6:01:39 AM #

I respect both Nick and David and think they are talking past each other.

  I used to use FreeAndNil(x) when I think that, it is possible that x is lazily created, because I often use the just-in-time-creation pattern on sub-objects in complex cases, because object x is not always even needed.  In such cases, x is created at first use.  I realize that x.Free on an object which is nil, is safe, but I cannot say for sure that the destructor that I am invoking does not assume that the object was created, and so, while x.Free; with x = nil is inherently safe for TObject, it's not inherently safe in a complex case in the real world.  FreeAndNil(x) is always safe, always.

Nobody is saying there are never good places to use FreeAndNil(x) but when someone uses it ALWAYS instead of assuming that "since I created it in the constructor, it will always exist, and even if it doesn't exist, I'm quite sure x.Free is safe even for the case when x is nil", then they can safely call x.free.

Warren

Warren P. Canada |

1/19/2012 10:55:21 PM #

x.Free is always safe for any type of nil

.Free is not a destructor.

.Free would call the destructing sequence (including calling .BeforeDestruction and .Destroy) on not-nil objects

for nil objects .Free would NOt call the destructor, so it remains safe to not check for Self=nil in destructors and still have x.Free safe.

However if you're sure the variable is not nil, then calling x.Destroy would make your code "be precise and say what needs to be said and nothing more".

Arioch Russia |

1/9/2012 9:19:47 AM #

I think you may be putting the horse before the cart and creating confusion by ranting about FreeAndNil. Your argument seems to be "If you use certain programming paradigms/tools like dependency injection and coding to abstractions/interfaces then you won't need to rely on FreeAndNil, and you will have more maintainable code as well". If I'm interpreting that correctly, then the FreeAndNil aspect of your argument seems to be completely irrelevant. If all programs were written with interfaces and dependency injection, then there would be no need to call Create or Free - or FreeAndNil for that matter. So, wouldn't it be much more beneficial to write an article explaining why dependency injection or programming to abstraction are good things or how to use them properly? I've found that it is far more useful to advocate FOR something than against something.

For example, at one point there were some pretty ridiculous wars regarding the goto statement. I'm betting that some of those arguments came about because "anti-goto" programmers (who we can all acknowledge now were right) were too busy ranting about the evils of the goto statement to explain all of the benefits of the other control statements. Once everyone started using the new control statements and realized that they could do pretty much everything that the goto could do and be more readable and easier to debug, then no one used goto anymore.

This is probably where the compliant of dogmatism comes about. I don't think you are being dogmatic - you sound like you have a well thought out position based on real world experience and not just a blind adherence to authority. However, your argument at a glance could look a bit like "FreeAndNil EVIL!", which sounds dogmatic whether it is or not.  

Also, you acknowledge that legacy code sometimes requires you to use FreeAndNil. I may be mistaken but I would guess that given the history of Delphi, many Delphi programmers are still working with legacy code with a long history. I personally would love to refactor my company's massive code base, which is now over a decade old. But that has to happen over time with adequate testing to minimize risk. If I lived in a world where I could start over from scratch in Delphi your advice would certainly be useful. Although, to be honest, if I did live in such a world I might not even consider Delphi in the first place.

praeus United States |

1/9/2012 12:30:32 PM #

I'd have to say that the most frequent use of FreeAndNil that I've seen is with global variables, and more specifically with non-modal forms in SDI apps.

Global variables are completely unnecessary in Delphi -- if you use them, you're just being lazy.

But the thing with global vars for non-modal forms is ... that's how the Delphi IDE itself generates its code!

It would really be nice if the IDE generated a project that used a factory, or even DI, to create and manage forms on a list, rather than have a global variable declared at the bottom of the Interface section of every single form file.  

Until that happens, people are more likely to leave that global variable in place, and employ FreeAndNil to manage instances of it.

I've suggested replacing these global form vars with something else, and in every single case I've been told something like, "That's how Delphi does it, and we'll only confuse maintenance programmers if we mess with it."

So anybody who wants to beat a drum to eliminate use of FreeAndNil should first get the people who maintain the freaking IDE to get with the program and stop generating code with global form vars in it just because that's how it was done back in 1995.

The IDE could do a lot of very intelligent encapsulation for us ... but it's got to start there.

David S United States |

1/15/2012 12:32:37 AM #

thanks for this

john United States |

1/16/2012 6:59:27 AM #

I note that Verity Stob has picked up on this great schism of our times: www.theregister.co.uk/.../print.html

David Heffernan United Kingdom |

1/17/2012 11:37:31 PM #

And made me LOL with that.
She deserves a free coffee.

EMB |

1/19/2012 8:02:20 AM #

subscribed to him, thsnks for the link Smile

Arioch Russia |

1/22/2012 2:36:01 AM #

The name Verity suggest a woman. But AFAIK, she is in reality a guy.

Rudy Velthuis Germany |

Pingbacks and trackbacks (1)+

Comments are closed

My Book

A Pithy Quote for You

"There's a fine line between fishing and just standing on the shore like an idiot."    –  Steve Wright

Amazon Gift Cards

General Disclaimer

The views I express here are entirely my own and not necessarily those of any other rational person or organization.  However, I strongly recommend that you agree with pretty much everything I say because, well, I'm right.  Most of the time. Except when I'm not, in which case, you shouldn't agree with me.