FreeAndNil to use or not to use

After reading these debates about FreeAndNil I separated the people into 
two categories:

The first one says: "You should have a perfect design which prohibits 
errors from happening. So, if you have a perfect design then FreeAndNil 
is not necessary so you should not use it. If we see FreeAndNil in your 
code then it means that your design is not perfect."

The second one says: "Yes, we agree that we should have a perfect design 
which prohibits errors from happening and we do our best in order to 
create a perfect design. However our practice says that it is better to 
have a perfect design AND various runtime checks active including 
FreeAndNil than to have only a perfect design".
0
Andrew
10/11/2010 5:17:04 AM
📁 embarcadero.delphi.rtl
📃 934 articles.
⭐ 0 followers.

💬 127 Replies
👁️‍🗨️ 2540 Views

> {quote:title=Andrew Fionik wrote:}{quote}
> After reading these debates about FreeAndNil I separated the people into 
> two categories:
> 
> The first one says: "You should have a perfect design which prohibits 
> errors from happening. So, if you have a perfect design then FreeAndNil 
> is not necessary so you should not use it. If we see FreeAndNil in your 
> code then it means that your design is not perfect."
> 
> The second one says: "Yes, we agree that we should have a perfect design 
> which prohibits errors from happening and we do our best in order to 
> create a perfect design. However our practice says that it is better to 
> have a perfect design AND various runtime checks active including 
> FreeAndNil than to have only a perfect design".

There is also a third category. You should not use FreeAndNil in destructors.
FreeAndNil in destructors is clear sign of very bad design. But there are perfectly
valid designs where FreeAndNil is used. 

I think Allen Bauer's blogs are nicely summarizing the problem:

http://blogs.embarcadero.com/abauer/2010/02/05/38910

http://blogs.embarcadero.com/abauer/2010/02/16/38916

Dalija Prasnikar
0
Dalija
10/11/2010 10:09:42 AM
On 11.10.2010 16:09, Dalija Prasnikar wrote:
> There is also a third category. You should not use FreeAndNil in destructors.
> FreeAndNil in destructors is clear sign of very bad design. But there are perfectly
> valid designs where FreeAndNil is used.
> I think Allen Bauer's blogs are nicely summarizing the problem:
> http://blogs.embarcadero.com/abauer/2010/02/05/38910
> http://blogs.embarcadero.com/abauer/2010/02/16/38916

I have read this discussion. In my classification the third category is 
a subset of the first one.
0
Andrew
10/11/2010 10:31:39 AM
> {quote:title=Andrew Fionik wrote:}{quote}
> On 11.10.2010 16:09, Dalija Prasnikar wrote:
> > There is also a third category. You should not use FreeAndNil in destructors.
> > FreeAndNil in destructors is clear sign of very bad design. But there are perfectly
> > valid designs where FreeAndNil is used.
> > I think Allen Bauer's blogs are nicely summarizing the problem:
> > http://blogs.embarcadero.com/abauer/2010/02/05/38910
> > http://blogs.embarcadero.com/abauer/2010/02/16/38916
> 
> I have read this discussion. In my classification the third category is 
> a subset of the first one.

Not entirely, but close enough. I would say that if you already have a design
filled with FreeAndNils in a destructors, than you very likely have a bad design.
On the other hand there are people using FreeAndNil in destructors, not because 
they are trying to fix some issues, but because they have picked it up from
someone without thinking. If I had to teach someone how to program, one of
the rules would be "do not call FreeAndNil just because you can". Use of FreeandNil
has to be well thought of.

So if you are dealing with a bad design it is perfectly understandable that it is not 
always viable to change it instantly. But if you are aware of a bad design, than you
can change it when the time comes, on the other hand if you have bad design and you 
are not aware of it you will probably repeat same mistakes in the future.

And if you are developing new piece of code need for FreeAndNil in the destructors
should be an early warning that you are doing things wrong way.

If you have more concrete questions about whether to use FreeAndNil or not, you may 
receive more concrete answers.

Dalija Prasnikar
0
Dalija
10/11/2010 10:47:39 AM
On 11.10.2010 16:09, Dalija Prasnikar wrote:
> There is also a third category. You should not use FreeAndNil in destructors.
> FreeAndNil in destructors is clear sign of very bad design. But there are perfectly
> valid designs where FreeAndNil is used.
> I think Allen Bauer's blogs are nicely summarizing the problem:
> http://blogs.embarcadero.com/abauer/2010/02/05/38910
> http://blogs.embarcadero.com/abauer/2010/02/16/38916

IMHO, a demonstration of the uselessness of FastMM and the recommended 
Allen's approach is below:

program Project1;

{$APPTYPE CONSOLE}

uses
   FastMM4,
   SysUtils;

type
   TA=class(TObject)
   strict private
     FIntValue:Integer;
   public
     constructor Create(const aIntValue:Integer);
     function GetIntValue:Integer;
   end;

{ TA }

constructor TA.Create(const aIntValue:Integer);
begin
   inherited Create;
   FIntValue:=aIntValue;
end;

function TA.GetIntValue: Integer;
begin
   Result:=FIntValue;
end;

var
   A:TA;
   I:Integer;
begin
   try
     A:=TA.Create(5);
     try
       WriteLn(A.GetIntValue);
     finally
       //FreeAndNil(A);
       A.Free;
     end;
     WriteLn(A.GetIntValue);
   except
     on E: Exception do
       Writeln(E.ClassName, ': ', E.Message);
   end;
   ReadLn;
end.

Execute it and it will work, though the results are wrong. Then change 
A.Free to the FreeAndNil(A) and you will get an access violation.

A second example shows that FastMM offers some protection, but the first 
example indicates that this protection is not full and FreeAndNil adds a 
certain amount of safety. So you can't rely entirely on FastMM and those 
QA Audits which aren't avaliable to us mere mortals.

program Project1;

{$APPTYPE CONSOLE}

uses
   FastMM4,
   SysUtils;

type
   TA=class(TObject)
   strict private
     FIntValue:Integer;
     FStrValue:string
   public
     function GetIntValue:Integer;
     function GetStrValue:string;
   public
     constructor Create(const aStrValue:string; const aIntValue: Integer);
   end;

{ TA }

constructor TA.Create(const aStrValue:string; const aIntValue:Integer);
begin
   inherited Create;
   FStrValue:=aStrValue;
   FIntValue:=aIntValue;
end;

function TA.GetIntValue: Integer;
begin
   Result:=FIntValue;
end;

function TA.GetStrValue: string;
begin
   Result:=FStrValue;
end;

var
   A:TA;
   I:Integer;
begin
   try
     A:=TA.Create('Hello world', 5);
     try
       WriteLn(A.GetIntValue);
       WriteLn(A.GetStrValue);
     finally
       //FreeAndNil(A);
       A.Free;
     end;
     WriteLn(A.GetIntValue);
     WriteLn(A.GetStrValue);
   except
     on E: Exception do
       Writeln(E.ClassName, ': ', E.Message);
   end;
   ReadLn;
end.

I'll be glad if somebody proves that I'm wrong.
0
Andrew
10/11/2010 10:54:39 AM
Dalija Prasnikar wrote:

> There is also a third category. You should not use FreeAndNil in destructors.
> FreeAndNil in destructors is clear sign of very bad design. But there are
> perfectly valid designs where FreeAndNil is used. 

Well, suppose you got a class that frees some embedded objects in it's
destructor, using just .Free .

There is a class deriving from this class. Inside it's destructor, after
calling inherited, it does something (e.g. freeing another embedded object
which was newly introduced in this derived class) which ends up calling some
method on this class (e.g. because of change notification mechanism) which ends
up accessing the embedded objects already freed in the inherited destructor.

Now, obviously, this is buggy code. No question about it.

But by just calling .Free, all the references to the embedded objects remain
"valid" (assuming the used memory manager doesn't directly call VirtualFree)
and the above code might appear to work without raising any exceptions.

Assuming code involved in the destructor doesn't allocate memory, this will
probably work most of the time (except in the rare cases where the FreeMem
caused by .Free ends up being for the last item in a block and the whole block
is deallocated using VirtualFree) for single-threaded applications.

But once you have a multi-threaded application, things can get really ugly when
the memory just freed inside your destructor gets reused by an allocation from
a different thread before the moment when the already freed object gets
accessed again from inside the destructors.

Depending on the exact pattern of read/write access, it's quite likely that any
AV or strange behaviour caused by this will show up in the context of whatever
poor thread ended up using that memory instead of the thread currently running
the destructor.

If FreeAndNil had been used instead of just .Free, the above scenario would
very likely result in an AV inside the destructor, even with when doing simple
simple-threaded testing, instead of having a hot mine buried in your code.

I DO fully agree that code that only works because FreeAndNil was used means
there is probably something wrong with the design.

On the other hand, using just .Free can result in a lot of code that is clearly
broken from seeming to run fine and only fall over once you get memory
allocations overlapping with the time window between freeing objects and when
they are last accessed after being freed.
0
Thorsten
10/11/2010 10:56:56 AM
Andrew,

On Mon, 11 Oct 2010 06:17:04 +0100, Andrew Fionik <[email protected]> wrote:

> After reading these debates about FreeAndNil I separated the people into
> two categories:
>
> The first one says: "You should have a perfect design which prohibits
> errors from happening. So, if you have a perfect design then FreeAndNil
> is not necessary so you should not use it. If we see FreeAndNil in your
> code then it means that your design is not perfect."
>
> The second one says: "Yes, we agree that we should have a perfect design
> which prohibits errors from happening and we do our best in order to
> create a perfect design. However our practice says that it is better to
> have a perfect design AND various runtime checks active including
> FreeAndNil than to have only a perfect design".

As you may have noticed, several contributors to this forum are vociferous  
advocates of the first position: "Real Programmers don't nil pointers" and  
are most dismissive of those who do...

>> If I see it, I am almost 100% sure to see code of someone who doesn't 
>> know enough about the lifetime of their objects

To which my response is "Au contraire!  Not only do I know exactly what I  
intend their lifetimes to be, but also I want to be certain that after I  
have killed them, they don't linger on in some zombie-like half-alive  
state". Actually that would be better expressed as, "if they do ever try  
to come back to life, that the alarm bells are rung as loudly as possible  
and as soon as possible."

(I'm not sure where this particular phobia comes from - perhaps when  
pregnant, their mother was frightened by some malformed Pascal code. Or  
maybe they are still feeling resentful about being told to tidy away their  
toys after they had used them.)

Strangely, they seem to exhibit no similar aversion to ASSERT or UnitTests  
or Compiler Error Messages - all of which are also completely superfluous  
if their design (and implementation) are so perfect.

-- 
Paul Scott
Information Management Systems
Macclesfield, UK
0
Paul
10/11/2010 11:14:39 AM
On 11.10.2010 17:14, Paul Scott wrote:
> Strangely, they seem to exhibit no similar aversion to ASSERT or UnitTests
> or Compiler Error Messages - all of which are also completely superfluous
> if their design (and implementation) are so perfect.

Well... actually if design is perfect (a perfect design prohibits errors 
from happening) then debugger is not needed also. :)
0
Andrew
10/11/2010 11:46:09 AM
> {quote:title=Andrew Fionik wrote:}{quote}
> On 11.10.2010 16:09, Dalija Prasnikar wrote:
> > There is also a third category. You should not use FreeAndNil in destructors.
> > FreeAndNil in destructors is clear sign of very bad design. But there are perfectly
> > valid designs where FreeAndNil is used.
> > I think Allen Bauer's blogs are nicely summarizing the problem:
> > http://blogs.embarcadero.com/abauer/2010/02/05/38910
> > http://blogs.embarcadero.com/abauer/2010/02/16/38916
> 
> IMHO, a demonstration of the uselessness of FastMM and the recommended 
> Allen's approach is below:
> 
> program Project1;
> 
> {$APPTYPE CONSOLE}
> 
> uses
>    FastMM4,
>    SysUtils;
> 
> type
>    TA=class(TObject)
>    strict private
>      FIntValue:Integer;
>    public
>      constructor Create(const aIntValue:Integer);
>      function GetIntValue:Integer;
>    end;
> 
> { TA }
> 
> constructor TA.Create(const aIntValue:Integer);
> begin
>    inherited Create;
>    FIntValue:=aIntValue;
> end;
> 
> function TA.GetIntValue: Integer;
> begin
>    Result:=FIntValue;
> end;
> 
> var
>    A:TA;
>    I:Integer;
> begin
>    try
>      A:=TA.Create(5);
>      try
>        WriteLn(A.GetIntValue);
>      finally
>        //FreeAndNil(A);
>        A.Free;
>      end;
>      WriteLn(A.GetIntValue);
>    except
>      on E: Exception do
>        Writeln(E.ClassName, ': ', E.Message);
>    end;
>    ReadLn;
> end.
> 
> Execute it and it will work, though the results are wrong. Then change 
> A.Free to the FreeAndNil(A) and you will get an access violation.
> 
> A second example shows that FastMM offers some protection, but the first 
> example indicates that this protection is not full and FreeAndNil adds a 
> certain amount of safety. So you can't rely entirely on FastMM and those 
> QA Audits which aren't avaliable to us mere mortals.
> 
> program Project1;
> 
> {$APPTYPE CONSOLE}
> 
> uses
>    FastMM4,
>    SysUtils;
> 
> type
>    TA=class(TObject)
>    strict private
>      FIntValue:Integer;
>      FStrValue:string
>    public
>      function GetIntValue:Integer;
>      function GetStrValue:string;
>    public
>      constructor Create(const aStrValue:string; const aIntValue: Integer);
>    end;
> 
> { TA }
> 
> constructor TA.Create(const aStrValue:string; const aIntValue:Integer);
> begin
>    inherited Create;
>    FStrValue:=aStrValue;
>    FIntValue:=aIntValue;
> end;
> 
> function TA.GetIntValue: Integer;
> begin
>    Result:=FIntValue;
> end;
> 
> function TA.GetStrValue: string;
> begin
>    Result:=FStrValue;
> end;
> 
> var
>    A:TA;
>    I:Integer;
> begin
>    try
>      A:=TA.Create('Hello world', 5);
>      try
>        WriteLn(A.GetIntValue);
>        WriteLn(A.GetStrValue);
>      finally
>        //FreeAndNil(A);
>        A.Free;
>      end;
>      WriteLn(A.GetIntValue);
>      WriteLn(A.GetStrValue);
>    except
>      on E: Exception do
>        Writeln(E.ClassName, ': ', E.Message);
>    end;
>    ReadLn;
> end.
> 
> I'll be glad if somebody proves that I'm wrong.

I am not sure if it is matter of proving, but rather a matter of opinion. 
IMHO above code is not even a question of a bad design, but a clear 
example of programmer sleeping on his job ;-)

Dalija Prasnikar
0
Dalija
10/11/2010 1:10:07 PM
> {quote:title=Thorsten Engler wrote:}{quote}
> Dalija Prasnikar wrote:
> 
> > There is also a third category. You should not use FreeAndNil in destructors.
> > FreeAndNil in destructors is clear sign of very bad design. But there are
> > perfectly valid designs where FreeAndNil is used. 
> 
> 
> I DO fully agree that code that only works because FreeAndNil was used means
> there is probably something wrong with the design.
> 
> On the other hand, using just .Free can result in a lot of code that is clearly
> broken from seeming to run fine and only fall over once you get memory
> allocations overlapping with the time window between freeing objects and when
> they are last accessed after being freed.

I am not apriori against using FreeAndNil. And certainly there are cases where it
can help catch bugs sooner than later. But such cases often are a sign of bad
design. And that is not uncommon in real world. When you are facing deadlines
you're bound to make some code, and then usually you have to patch things 
up making some more code ;-)

I am against using FreeAndNil all over the place just because it could reveal some bugs.
If you delusion yourself that using FreeAndNil will be some sort of safe net, then sooner
or later you will get into some real trouble. Of course, this is my opinion, and I am not trying
to make it everyone elses, but I am also not going to change it. I think the main problem with 
FreeAndNil is that people tend to use it without thinking.

If I write bad code (and I certainly have) I always mark it as such. That way I can redesign things 
later, and I can pay special attention to those parts of code. And if I use FreeAndNil by 
design (reusable objects) I clearly mark that code also. 

Dalija Prasnikar
0
Dalija
10/11/2010 1:32:11 PM
On 11.10.2010 19:10, Dalija Prasnikar wrote:
> I am not sure if it is matter of proving, but rather a matter of opinion.
> IMHO above code is not even a question of a bad design, but a clear
> example of programmer sleeping on his job ;-)

That's why FreeAndNil is useful, exactly on unconscious level. Today you 
sleep at job, tomorrow FreeAndNil will save you. A programmer whose 
design is perfect tears out his hair in search for a mysterious error 
which happens somewhere else. A programmer who uses FreeAndNil without 
much of thinking (including destructors and finally clauses) simply 
wonders if he was drunk on previous day and fixes the wrong code in 
seconds.

We all do errors.
0
Andrew
10/11/2010 1:32:42 PM
> {quote:title=Andrew Fionik wrote:}{quote}
> On 11.10.2010 17:14, Paul Scott wrote:
> > Strangely, they seem to exhibit no similar aversion to ASSERT or UnitTests
> > or Compiler Error Messages - all of which are also completely superfluous
> > if their design (and implementation) are so perfect.
> 
> Well... actually if design is perfect (a perfect design prohibits errors 
> from happening) then debugger is not needed also. :)

LOL

Dalija Prasnikar
0
Dalija
10/11/2010 1:32:50 PM
> IMHO, a demonstration of the uselessness of FastMM and the recommended
> Allen's approach is below:

I guess you have to think a little about how AV's get generated at all...


> var
>     A:TA;
>     I:Integer;
> begin
>     try
>       A:=TA.Create(5);
>       try
>         WriteLn(A.GetIntValue);
>       finally
>         //FreeAndNil(A);
>         A.Free;
>       end;
>       WriteLn(A.GetIntValue);
>     except
>       on E: Exception do
>         Writeln(E.ClassName, ': ', E.Message);
>     end;
>     ReadLn;
> end.

This will most likely never result in an access violation since - 
although you release the memory - the memory block allocated by
VirtualAlloc is still attached to the program thus for windows it's
a perfectly valid memory access (and normally only windows throws these
exceptions). AFAIK FastMM would raise an exception if you call Free a 
second time but why should FastMM know anything about the call to 
A.gEtIntValue?

This would (can) only fail if the memory manager deallocates the 
complete memory block it got using the VirtualAlloc (or similar) calls - 
by the way although one can set the size in bytes in the Virtualalloc 
call the function will always round up this parameter to the next 
pagesize (which is normally 4kB!) and no memory manager will
dare to always lock a 4kB page for one small object (thats basically his
main duty).



> program Project1;
>
> {$APPTYPE CONSOLE}
>
> uses
>     FastMM4,
>     SysUtils;
>
> type
>     TA=class(TObject)
>     strict private
>       FIntValue:Integer;
>       FStrValue:string
>     public
>       function GetIntValue:Integer;
>       function GetStrValue:string;
>     public
>       constructor Create(const aStrValue:string; const aIntValue: Integer);
>     end;
>
> { TA }
>
> constructor TA.Create(const aStrValue:string; const aIntValue:Integer);
> begin
>     inherited Create;
>     FStrValue:=aStrValue;
>     FIntValue:=aIntValue;
> end;
>
> function TA.GetIntValue: Integer;
> begin
>     Result:=FIntValue;
> end;
>
> function TA.GetStrValue: string;
> begin
>     Result:=FStrValue;
> end;
>
> var
>     A:TA;
>     I:Integer;
> begin
>     try
>       A:=TA.Create('Hello world', 5);
>       try
>         WriteLn(A.GetIntValue);
>         WriteLn(A.GetStrValue);
>       finally
>         //FreeAndNil(A);
>         A.Free;
>       end;
>       WriteLn(A.GetIntValue);
>       WriteLn(A.GetStrValue);

What should happen here - I didn't get any exception (except an empty 
string output) using Delphi2007....

kind regards
    Mike
0
Michael
10/11/2010 3:28:37 PM
On Mon, 11 Oct 2010 12:46:09 +0100, Andrew Fionik <[email protected]> wrote:

>> Strangely, they seem to exhibit no similar aversion to ASSERT  or  
>> UnitTests or Compiler Error Messages - all of which are alsocompletely  
>> superfluous if their design (and implementation) areso perfect.
>
> Well... actually if design is perfect (a perfect design prohibitserrors  
> from happening) then debugger is not needed also. :)

I forgot about that other non-essential :)

But I doubt that even perfect designs can counteract the effects of  
gravity - and stop coffee mugs falling on a keyboard and messing up  
otherwise perfect code.

-- 
Paul Scott
Information Management Systems
Macclesfield, UK
0
Paul
10/11/2010 3:56:04 PM
> {quote:title=Andrew Fionik wrote:}{quote}
> After reading these debates about FreeAndNil I separated the people into 
> two categories:
> 
I virtually never use FreeAndNil. If I need to reset the value of an object reference to nil then I use an explicit assignment statement:

ObjectArry[i].Free;
ObjectArray[i]:= nil;

This prevents me from working in autopilot and  think about why I am resetting a released object reference to nil. Clearly assigning an object owned by another object to nil in the destructor of the owner object is unnecessary. It should not normally be harmful, but is poor programming. However setting an object reference to nil after the object has been released because we need to retain the reference and possibly query it later to determine whether or not it points to an object is essential. So there is
 no rule that fits all situations.

The argument about poor design could also be levelled at the use of Free in stead of Destroy. In a well designed program there should be no need to check whether or not an object is nil when Destroy is called. It should always exist. And yet in the on-line help of the version of Delphi that I use, it is recommended that Free should always be used in preference to Destroy. I frequently ignore this defensive tactic and I don't suffer many runtime exceptions because of it.

EM
0
Enquiring
10/11/2010 6:02:48 PM
Andrew Fionik wrote:
> After reading these debates about FreeAndNil I separated the people
> into two categories:
> 
> The first one says: "You should have a perfect design which prohibits
> errors from happening. So, if you have a perfect design then
> FreeAndNil is not necessary so you should not use it. If we see
> FreeAndNil in your code then it means that your design is not
> perfect." 

IMO nonsense, search the Delphi RTL, it uses FreeAndNil at many
places. 
Actually using FreeAndNil rather than .Free when .Free was
enough is just a little bit slower. And I agree that it should be avoided
if possible but there are many use cases where FreeAndNil makes
sense. If you create objects dynamically when they are needed a 
nil or non-nil object pointer indicates whether you have an
object or not. Last but not least you'll get a very clear AV on the attempt
to dereference a nil object pointer, which makes debugging much easier. 

My two cents.

-- 
Arno Garrels
0
Arno
10/11/2010 6:17:11 PM
> {quote:title=Andrew Fionik wrote:}{quote}
> On 11.10.2010 19:10, Dalija Prasnikar wrote:
> > I am not sure if it is matter of proving, but rather a matter of opinion.
> > IMHO above code is not even a question of a bad design, but a clear
> > example of programmer sleeping on his job ;-)
> 
> That's why FreeAndNil is useful, exactly on unconscious level. Today you 
> sleep at job, tomorrow FreeAndNil will save you. A programmer whose 
> design is perfect tears out his hair in search for a mysterious error 
> which happens somewhere else. A programmer who uses FreeAndNil without 
> much of thinking (including destructors and finally clauses) simply 
> wonders if he was drunk on previous day and fixes the wrong code in 
> seconds.
> 
> We all do errors.

I would agree with that if FreeAndNil used in wrong place wouldn't obscure code
where it really needs to be used. If you are writing your own code you and you know
what you are doing, that may be fine, but it is not an easy job to go through someone
else's code that is polluted with FreeAndNil's and every single time you encounter it you
need to ask why is this here?

BTW, when I am sleeping and working not even FreeAndNil can save me ;-)

And so far in more than 20 years of programming I didn't make such errors where
FreeAndNil would save my day. Maybe I'm just lucky :)

Dalija Prasnikar
0
Dalija
10/11/2010 6:25:13 PM
On 11.10.2010 21:28, Michael Rabatscher wrote:
>  AFAIK FastMM would raise an exception if you call Free a
> second time but why should FastMM know anything about the call to
> A.gEtIntValue?

That's why using only FastMM isn't enough. FreeAndNil - good addition.

> What should happen here - I didn't get any exception (except an empty
> string output) using Delphi2007....

Things are becoming interesting. Are you sure that you run it in 
FullDebug mode? The EAV exception should be raised on GetStrValue.
0
Andrew
10/12/2010 2:19:20 AM
On 12.10.2010 0:02, Enquiring Mind wrote:
> This prevents me from working in autopilot and  think about why I am resetting a released object reference to nil.

Why think about "why I'm resetting a released object reference to nil"? 
How using FreeAndNil could make your things worse?

> Clearly assigning an object owned by another object to nil in the destructor of the owner object is unnecessary. It should not normally be harmful, but is poor programming.

Why? Why technique which adds a certain level of protection is called 
"poor programming"? Especially if it costs almost nothing.
0
Andrew
10/12/2010 2:24:24 AM
Am 12.10.2010 04:19, schrieb Andrew Fionik:
> On 11.10.2010 21:28, Michael Rabatscher wrote:
>>   AFAIK FastMM would raise an exception if you call Free a
>> second time but why should FastMM know anything about the call to
>> A.gEtIntValue?
>
> That's why using only FastMM isn't enough. FreeAndNil - good addition.

Apart of all that discussion I'm not a big Fan of FreeAndNil either - I 
only use it if I got some class object variable which is cleared in one
function and set in another one and this mostly happens because I'm 
sometimes a bit lazy (shame on me).

>
>> What should happen here - I didn't get any exception (except an empty
>> string output) using Delphi2007....
>
> Things are becoming interesting. Are you sure that you run it in
> FullDebug mode? The EAV exception should be raised on GetStrValue.

The downloaded version indeed seems to raise an exception but as far as
I can see the FastMM version included in Delphi2007 does not.
In full debug mode I think the "CheckHeapForCorruption" and also the 
"FullDebugMode" option is set where some extended heap checks are performed.

kind regards
    Mike
0
Michael
10/12/2010 7:49:47 AM
> I virtually never use FreeAndNil. If I need to reset the value of an object reference to nil then I use an explicit assignment statement:
>
> ObjectArry[i].Free;
> ObjectArray[i]:= nil;

You eventually should - FreeAndNil works a bit different than your 
implementation. It first sets the variable to nil and then frees the
object. My guess is that this approach is better in case an exception
happens in the destructor - it basically prevents the user from double
freeing the object.

kind regards
    Mike
0
Michael
10/12/2010 8:09:10 AM
On 12.10.2010 13:49, Michael Rabatscher wrote:
>> Things are becoming interesting. Are you sure that you run it in
>> FullDebug mode? The EAV exception should be raised on GetStrValue.
>
> The downloaded version indeed seems to raise an exception but as far as
> I can see the FastMM version included in Delphi2007 does not.
> In full debug mode I think the "CheckHeapForCorruption" and also the
> "FullDebugMode" option is set where some extended heap checks are performed.

Anyway, different modes, different versions of Delphi and you get 
different results. Sometimes you get the partial protection by FastMM, 
sometimes you don't. But with FreeAndNil you get it always, then why 
hesitate to use it?
0
Andrew
10/12/2010 8:59:38 AM
> Anyway, different modes, different versions of Delphi and you get
> different results. Sometimes you get the partial protection by FastMM,
> sometimes you don't. But with FreeAndNil you get it always, then why
> hesitate to use it?

So far I have followed the discussion my impressino is that this trend 
is against some peoples self imposed coding guidelines.
For me coding is, when it becomes to such nitty picky details, good if
you always follow the same rules. There is another thread in BASM
group where people try to find pro's and cons against letting the
memory manger zeroing out everything before and after a getmem/freemem
call - it's again nothing very important but from my point of view again
something which has to do with coding styles.

So you will find always pro's and con's against a certain design pattern 
;) but hopefully you will always do it the same way - otherwise you will 
find yourself sometime in coding hell ;)

kind regards
    Mike
0
Michael
10/12/2010 9:24:45 AM
On Mon, 11 Oct 2010 19:02:48 +0100, Enquiring Mind  wrote:

> The argument about poor design could also be levelled at the use of Free  
> instead of Destroy. In a well designed program there should be no need  
> to check whether or not an object is nil when Destroy is called. It  
> should always exist. And yet in the on-line help of the version of  
> Delphi that I use, it is recommended that Free should always be used in  
> preference to Destroy.

Yes, I do find it irritating that the same people who claim FreeAndNil is  
prima-facie evidence that the programmer doesn't understand object  
lifetimes don't appear able to see any flaw in the commonly-quoted  
template...

{code}

   with  tSomething.Create  do
     try
       ...

     finally
       Free
     end

{code}

Why the use of "Free"?  In order for that line of code to be executed, the  
instance *must* exist

-- 
Paul Scott
Information Management Systems
Macclesfield, UK
0
Paul
10/12/2010 9:30:24 AM
Paul Scott wrote:

> {code}
>  with  tSomething.Create  do
>    try
>      ...
>    finally
>      Free
>    end
> {code}
> 
> Why the use of "Free"?

Because that it the ultimate standard way to "free" an object.

> In order for that line of code to be executed, the instance must exist

No, Free will execute even if the instance doesn't exists. Now the
standard TObject behaviour is to check to see if Self <> nil before
calling Destroy, there are Components (even in the VCL/RTL) which does
some extra work in the Free.

You might say calling Free is a good habit (FreeAndNil is of course
useless in the above example) despite the use of the with statement,
not calling Free (and instead using Destroy directly) might have some
serious side-affects in some cases.

-- 
Pieter

"C++ tries to guard against Murphy, not Machiavelli." 
 -- Damian Conway
0
Pieter
10/16/2010 12:06:02 AM
Michael Rabatscher wrote:

> There is another thread in BASM
> group where people try to find pro's and cons against letting the
> memory manger zeroing out everything before and after a getmem/freemem
> call - it's again nothing very important but from my point of view
> again something which has to do with coding styles.

If you did have a serious look at that thread you should know it wasn't
just about merely zeroing all memory (although this was what the OP
might be referring too in his OP, it doesn't appear to be his end-goal).

To me this discussion "ended" that it needs some adjustments/changes in
the RTL and some serious debugging/profiling.

IOW this discussion was not about the (ab)use of FreeAndNil.

-- 
Pieter

"The trouble with having an open mind, of course, is that people 
 will insist on coming along and trying to put things in it."
 -- Terry Pratchett
0
Pieter
10/16/2010 1:09:24 AM
Andrew Fionik wrote:

> After reading these debates about FreeAndNil I separated the people
> into two categories:
> 
> The first one says: "You should have a perfect design which prohibits 
> errors from happening. So, if you have a perfect design then
> FreeAndNil is not necessary so you should not use it. If we see
> FreeAndNil in your code then it means that your design is not
> perfect."
> 
> The second one says: "Yes, we agree that we should have a perfect
> design which prohibits errors from happening and we do our best in
> order to create a perfect design. However our practice says that it
> is better to have a perfect design AND various runtime checks active
> including FreeAndNil than to have only a perfect design".

You may have missed category three: those who are using FreeAndNil
blindly without knowing what they are doing because it accidentally
fixed a problem they had before (when talking about a multi-threaded
application they were most-likely just lucky).

-- 
Pieter

Hoare's Law Of Large Programs: Inside every large program is a 
small program struggling to get out.
0
Pieter
10/16/2010 1:40:01 AM
On 16.10.2010 7:40, Pieter Zijlstra wrote:
> You may have missed category three: those who are using FreeAndNil
> blindly without knowing what they are doing because it accidentally
> fixed a problem they had before (when talking about a multi-threaded
> application they were most-likely just lucky).

I have NEVER stated anywhere that FreeAndNil FIXES anyhing. I'll write 
it again. FreeAndNil DOES NOT FIX anything. FreeAndNil creates a 
condition which raises chances of a programmer to detect his own errors 
on early stage irrelevant to anything else. Nothing more. You and Rudy 
constantly forget about this. It is the same tool just like the Assert 
routine, the debugger or a memory manager in debugging mode.
0
Andrew
10/16/2010 6:29:15 AM
> {quote:title=Andrew Fionik wrote:}{quote}
> On 16.10.2010 7:40, Pieter Zijlstra wrote:
> > You may have missed category three: those who are using FreeAndNil
> > blindly without knowing what they are doing because it accidentally
> > fixed a problem they had before (when talking about a multi-threaded
> > application they were most-likely just lucky).
> 
> I have NEVER stated anywhere that FreeAndNil FIXES anyhing. I'll write 
> it again. FreeAndNil DOES NOT FIX anything. FreeAndNil creates a 
> condition which raises chances of a programmer to detect his own errors 
> on early stage irrelevant to anything else. Nothing more. You and Rudy 
> constantly forget about this. It is the same tool just like the Assert 
> routine, the debugger or a memory manager in debugging mode.

In decently written software chances that FreeAndNil would help you find some
errors are very slim. I don't use FreeAndNil for that and I have never had an error
where FreeAndNil would have helped me.

There is a difference between Assert and FreeAndNil. If you encounter Assert
in code it is obviuos what it means. On the other hand if you encounter FreeAndNil
in the code, especially in the place where you are not expecting one, only conclusion
could be that this code has some serious design flaws, or it is beeing written by
incompetent programmer who doesn't know where and why he should use
FreeAndNil. Using FreeAndNil all the time is polluting the code and makes it 
hard to understand. Debugging is completely different stuff, it is a tool that is not 
messing up your code.

If you want to use FreeAndNil in the early stages of development, OK, but IMHO it is 
still a bad practice. But leaving it in your code when it is finished is a BAD move.
And IMHO, is even worse to teach newbies to use it because it will fix something
they have messed up.

(I am not talking about special cases where FreeAndNil is used by design and has 
to be there)

Dalija Prasnikar
0
Dalija
10/16/2010 9:29:09 AM
> {quote:title=Andrew Fionik wrote:}{quote}
> On 16.10.2010 7:40, Pieter Zijlstra wrote:
> > You may have missed category three: those who are using FreeAndNil
> > blindly without knowing what they are doing because it accidentally
> > fixed a problem they had before (when talking about a multi-threaded
> > application they were most-likely just lucky).
> 
> I have NEVER stated anywhere that FreeAndNil FIXES anyhing. I'll write 
> it again. FreeAndNil DOES NOT FIX anything. FreeAndNil creates a 
> condition which raises chances of a programmer to detect his own errors 
> on early stage irrelevant to anything else. Nothing more. You and Rudy 
> constantly forget about this. It is the same tool just like the Assert 
> routine, the debugger or a memory manager in debugging mode.

I know that you haven't stated that FreeAndNil FIXES stuff. But You are
saying that FreeAndNil is helpfull. I am saying it is not.

Dalija Prasnikar
0
Dalija
10/16/2010 9:32:30 AM
On 16/10/2010 8:29 PM, Dalija Prasnikar wrote:
> There is a difference between Assert and FreeAndNil. If you encounter Assert
> in code it is obviuos what it means. On the other hand if you encounter FreeAndNil
> in the code, especially in the place where you are not expecting one, only conclusion
> could be that this code has some serious design flaws, or it is beeing written by
> incompetent programmer who doesn't know where and why he should use
> FreeAndNil. Using FreeAndNil all the time is polluting the code and makes it
> hard to understand.

This is a circular argument: using FreeAndNil indicates that the program 
is badly designed (and the programmer is incompetent), therefore using 
FreeAndNil is bad.

And why

   FreeAndNil(Something);

is somehow harder to understand than

   Something.Free;

completely escapes me.

--Rob.
0
Rob
10/16/2010 10:03:25 AM
> {quote:title=Rob McDonell wrote:}{quote}
> On 16/10/2010 8:29 PM, Dalija Prasnikar wrote:
> > There is a difference between Assert and FreeAndNil. If you encounter Assert
> > in code it is obviuos what it means. On the other hand if you encounter FreeAndNil
> > in the code, especially in the place where you are not expecting one, only conclusion
> > could be that this code has some serious design flaws, or it is beeing written by
> > incompetent programmer who doesn't know where and why he should use
> > FreeAndNil. Using FreeAndNil all the time is polluting the code and makes it
> > hard to understand.
> 
> This is a circular argument: using FreeAndNil indicates that the program 
> is badly designed (and the programmer is incompetent), therefore using 
> FreeAndNil is bad.
> 

FreeAndNil has its place in programming. But it is often misused as a bug
finder or bug fixer or whatever. Using FreeAndNil is not bad if you use it 
properly. But if you have code where FreeAndNil is misused you can easily 
overlook the code where it is used as part of the design. 

> And why
> 
>    FreeAndNil(Something);
> 
> is somehow harder to understand than
> 
>    Something.Free;
> 
> completely escapes me.
> 

It is not harder to understand, but it raises the question "Why is this object niled?" 
And it obscures real meaning of the code.

Dalija Prasnikar
0
Dalija
10/16/2010 11:47:32 AM
"Dalija Prasnikar" wrote
....................
> FreeAndNil has its place in programming. But it is often misused as a bug
> finder or bug fixer or whatever. Using FreeAndNil is not bad if you use it
> properly. But if you have code where FreeAndNil is misused you can easily
> overlook the code where it is used as part of the design.
>
>> And why
>>
>>    FreeAndNil(Something);
>>
>> is somehow harder to understand than
>>
>>    Something.Free;
>>
>> completely escapes me.
>>
>
> It is not harder to understand, but it raises the question "Why is this 
> object niled?"
> And it obscures real meaning of the code.

I sometimes use FreeAndNil in my code, and now I wonder in which group of 
programmers I belong: Those who use FreeAndnil for an acceptable reason or 
those who abuse it?

As far as I know FreeAndNil NEVER operates on an object; it operates on a 
pointer to an object.

And again as far as I know FreAndNil is a convenient way of invalidate this 
pointer after the pointed to object has been freed? The pointer can then 
serve as a semaphore telling if the object "exists". I have seen many 
subroutines testing a pointer argument for "nil" for just this purpose.

The only situation where I can see a problem with this is if the application 
has several pointers to the same object because FreeAndNil obviously cannot 
invalidate other pointers than the one operated on. (I never use FreeAndNil 
to free any object that is referenced through more than one pointer in my 
application).

OK?
0
Sven
10/16/2010 2:06:25 PM
> {quote:title=Sven Pran wrote:}{quote}
> "Dalija Prasnikar" wrote
> ...................
> > FreeAndNil has its place in programming. But it is often misused as a bug
> > finder or bug fixer or whatever. Using FreeAndNil is not bad if you use it
> > properly. But if you have code where FreeAndNil is misused you can easily
> > overlook the code where it is used as part of the design.
> >
> >> And why
> >>
> >>    FreeAndNil(Something);
> >>
> >> is somehow harder to understand than
> >>
> >>    Something.Free;
> >>
> >> completely escapes me.
> >>
> >
> > It is not harder to understand, but it raises the question "Why is this 
> > object niled?"
> > And it obscures real meaning of the code.
> 
> I sometimes use FreeAndNil in my code, and now I wonder in which group of 
> programmers I belong: Those who use FreeAndnil for an acceptable reason or 
> those who abuse it?
> 
> As far as I know FreeAndNil NEVER operates on an object; it operates on a 
> pointer to an object.
> 
> And again as far as I know FreAndNil is a convenient way of invalidate this 
> pointer after the pointed to object has been freed? The pointer can then 
> serve as a semaphore telling if the object "exists". I have seen many 
> subroutines testing a pointer argument for "nil" for just this purpose.
> 
> The only situation where I can see a problem with this is if the application 
> has several pointers to the same object because FreeAndNil obviously cannot 
> invalidate other pointers than the one operated on. (I never use FreeAndNil 
> to free any object that is referenced through more than one pointer in my 
> application).
> 
> OK?

From what you have written I guess that you are using it for acceptable reasons.
But it can be hard to tell exactly without real code. The one of the common way of
abuse is using FreeAndNil in the class destructor. 

BTW, I am also using FreeAndNil in some cases, mostly when nil is a valid state of an object
variable and actions are choosen depending on the value of that variable. 
For instance, if I have inner object in a class that is created upon some request, and later
discarded (while outer object is still in use), and if it could be requested again.

Dalija Prasnikar
0
Dalija
10/16/2010 2:50:58 PM
On 16.10.2010 17:47, Dalija Prasnikar wrote:
> It is not harder to understand, but it raises the question "Why is this object niled?"

The answer is very simple "Because I want to get EAV in case if I 
accidentally try to use this object".

> And it obscures real meaning of the code.

This is the only meaning.
0
Andrew
10/16/2010 3:45:00 PM
On 16.10.2010 20:06, Sven Pran wrote:
> The only situation where I can see a problem with this is if the application
> has several pointers to the same object because FreeAndNil obviously cannot
> invalidate other pointers than the one operated on.(I never use FreeAndNil
> to free any object that is referenced through more than one pointer in my
> application).

Neither Free. So this part is irrelevant to FreeAndNil and Free.
0
Andrew
10/16/2010 3:46:22 PM
"Dalija Prasnikar" wrote
>> {quote:title=Sven Pran wrote:}{quote}
>> "Dalija Prasnikar" wrote
>> ...................
>> I sometimes use FreeAndNil in my code, and now I wonder in which group of
>> programmers I belong: Those who use FreeAndnil for an acceptable reason 
>> or
>> those who abuse it?
>>
>> As far as I know FreeAndNil NEVER operates on an object; it operates on a
>> pointer to an object.
>>
>> And again as far as I know FreAndNil is a convenient way of invalidate 
>> this
>> pointer after the pointed to object has been freed? The pointer can then
>> serve as a semaphore telling if the object "exists". I have seen many
>> subroutines testing a pointer argument for "nil" for just this purpose.
>>
>> The only situation where I can see a problem with this is if the 
>> application
>> has several pointers to the same object because FreeAndNil obviously 
>> cannot
>> invalidate other pointers than the one operated on. (I never use 
>> FreeAndNil
>> to free any object that is referenced through more than one pointer in my
>> application).
>>
>> OK?
>
> From what you have written I guess that you are using it for acceptable 
> reasons.

Thanks, your example at the end below is typical.

> But it can be hard to tell exactly without real code. The one of the 
> common way of
> abuse is using FreeAndNil in the class destructor.

Christ - NO! (Wouldn't that lead to a recursive destructor call?)

> BTW, I am also using FreeAndNil in some cases, mostly when nil is a valid 
> state of an object
> variable and actions are choosen depending on the value of that variable.
> For instance, if I have inner object in a class that is created upon some 
> request, and later
> discarded (while outer object is still in use), and if it could be 
> requested again.

regards Sven
0
Sven
10/16/2010 4:12:03 PM
> {quote:title=Sven Pran wrote:}{quote}
> "Dalija Prasnikar" wrote
> 
> > But it can be hard to tell exactly without real code. The one of the 
> > common way of
> > abuse is using FreeAndNil in the class destructor.
> 
> Christ - NO! (Wouldn't that lead to a recursive destructor call?)
> 

That would really be a self destruction ;-)
No, when I am talking about not using FreeAndNil in a destructor I mean
don't use it to Free other objects. For instance

{code}
destructor TOuterClass.Destroy;
begin
  InnerObject.Free;
  inherited Destroy;
end;
{code}

Using FreeAndNil on InnerObject would definitively be abusing FreeAndNil.
At that point if you still have references to InnerObject that really means that
you are dealing with badly designed code, and if you don't there is no point in
calling FreeAndNil because it makes harder to understand what programmer
wanted to say (write).

Dalija Prasnikar
0
Dalija
10/16/2010 7:11:08 PM
> {quote:title=Andrew Fionik wrote:}{quote}
> On 16.10.2010 17:47, Dalija Prasnikar wrote:
> > It is not harder to understand, but it raises the question "Why is this object niled?"
> 
> The answer is very simple "Because I want to get EAV in case if I 
> accidentally try to use this object".
> 

This is not the question I had in mind. If I see such code I wonder if there 
are dangling references to this object, and if there are then the design is bad
and if design is bad, who knows what else is not right with this code.
And if there are no dangling references, and the design is perfect, and 
FreeAndNil is just sitting there doing nothing, that means I would be 
spending my time badly, trying to see if something that is not broken 
needs a fix.

If there is a chance that you may accidentaly use this object after it is
destroyed in destructor of another object than you are dealing with 
seriously bad design. I am not saying that such code does not exist, and
that it should be redesigned at once. But if you have such code and you do
need to use FreeAndNil to capture possible errors than such code should 
be redesigned as soon as possible. If you are writing new code, and you have 
the feeling that FreeAndNil would be of some use than you should drop that 
design at once and try something else. 

> > And it obscures real meaning of the code.
> 
> This is the only meaning.

Maybe to you, but not to others reading your code, and after a while even
you may begin to wonder what it really means.

Dalija Prasnikar
0
Dalija
10/16/2010 7:22:48 PM
"Dalija Prasnikar" wrote
>> > But it can be hard to tell exactly without real code. The one of the
>> > common way of
>> > abuse is using FreeAndNil in the class destructor.
>>
>> Christ - NO! (Wouldn't that lead to a recursive destructor call?)
>>
>
> That would really be a self destruction ;-)
> No, when I am talking about not using FreeAndNil in a destructor I mean
> don't use it to Free other objects. For instance

And if such "inner" objects were "owned" by the outer object (as they 
should), then no explicit free for the inner object would ever be needed in 
the outer object destructor?
0
Sven
10/16/2010 7:24:12 PM
> {quote:title=Sven Pran wrote:}{quote}
> "Dalija Prasnikar" wrote
> >> > But it can be hard to tell exactly without real code. The one of the
> >> > common way of
> >> > abuse is using FreeAndNil in the class destructor.
> >>
> >> Christ - NO! (Wouldn't that lead to a recursive destructor call?)
> >>
> >
> > That would really be a self destruction ;-)
> > No, when I am talking about not using FreeAndNil in a destructor I mean
> > don't use it to Free other objects. For instance
> 
> And if such "inner" objects were "owned" by the outer object (as they 
> should), then no explicit free for the inner object would ever be needed in 
> the outer object destructor?

That depends on the object type. If InnerObject is TComponent descendent
and OuterObject is also TComponent descendent and InnerObject owner then
OuterObject will destroy it and no explicit Free is needed. Howewer, if InnerObject 
is decnendent of some other type that does not handle owned objects destruction
automatically, or if InnerObject owner is nil, then Free shoud be called or you will have
memory leaks. For instance, if InnerObject is TStringList Free should be called explicitly.

Dalija Prasnikar
0
Dalija
10/16/2010 7:39:12 PM
"Dalija Prasnikar" wrote
..................
> Maybe to you, but not to others reading your code, and after a while even
> you may begin to wonder what it really means.

May I add one of my own experiences here:

Just for the record (and really not relevant for my story, but only to show 
that I am not without experience with computers): I designed and wrote my 
very first computer program in January 1964.

At one time in the seventies I had to go through a program for some reason 
(I no longer remember why) and began wondering who in our group had written 
this silly code; only to discover that it was myself 6 months earlier!

regards Sven
0
Sven
10/16/2010 9:23:41 PM
> {quote:title=Sven Pran wrote:}{quote}
> "Dalija Prasnikar" wrote
> .................
> > Maybe to you, but not to others reading your code, and after a while even
> > you may begin to wonder what it really means.
> 
> May I add one of my own experiences here:
> 
> Just for the record (and really not relevant for my story, but only to show 
> that I am not without experience with computers): I designed and wrote my 
> very first computer program in January 1964.
> 
> At one time in the seventies I had to go through a program for some reason 
> (I no longer remember why) and began wondering who in our group had written 
> this silly code; only to discover that it was myself 6 months earlier!
> 

This kind of thing is boud to happen sooner or later ;-)

One of the many reasons I love Pascal and Delphi is that understanding of 
written code lasts much, much longer. And you can even understand someone
elses code without banging your head against the wall ;-)
When I am writting something in assembler I tend to document every single line.

Dalija Prasnikar
0
Dalija
10/16/2010 9:35:22 PM
"Dalija Prasnikar" wrote in message news:[email protected]
>> {quote:title=Sven Pran wrote:}{quote}
>> "Dalija Prasnikar" wrote
>> .................
>> > Maybe to you, but not to others reading your code, and after a while 
>> > even
>> > you may begin to wonder what it really means.
>>
>> May I add one of my own experiences here:
>>
>> Just for the record (and really not relevant for my story, but only to 
>> show
>> that I am not without experience with computers): I designed and wrote my
>> very first computer program in January 1964.
>>
>> At one time in the seventies I had to go through a program for some 
>> reason
>> (I no longer remember why) and began wondering who in our group had 
>> written
>> this silly code; only to discover that it was myself 6 months earlier!
>>
>
> This kind of thing is boud to happen sooner or later ;-)
>
> One of the many reasons I love Pascal and Delphi is that understanding of
> written code lasts much, much longer. And you can even understand someone
> elses code without banging your head against the wall ;-)
> When I am writting something in assembler I tend to document every single 
> line.
>
> Dalija Prasnikar

The program I referred to was indeed written in Assembler (for IBM 
System/360) and was the direct reason why I later always wrote documenting 
comments on absolutely every single line in my ASM programs. 8-)
0
Sven
10/16/2010 10:36:37 PM
On 17/10/2010 6:22 AM, Dalija Prasnikar wrote:
> This is not the question I had in mind. If I see such code I wonder if there
> are dangling references to this object, and if there are then the design is bad
> and if design is bad, who knows what else is not right with this code.
> And if there are no dangling references, and the design is perfect, and
> FreeAndNil is just sitting there doing nothing, that means I would be
> spending my time badly, trying to see if something that is not broken
> needs a fix.

Well, it seems to me you're reading *way* too much into a simple FreeAndNil.

--Rob.
0
Rob
10/17/2010 1:26:16 AM
> {quote:title=Rob McDonell wrote:}{quote}
> On 17/10/2010 6:22 AM, Dalija Prasnikar wrote:
> > This is not the question I had in mind. If I see such code I wonder if there
> > are dangling references to this object, and if there are then the design is bad
> > and if design is bad, who knows what else is not right with this code.
> > And if there are no dangling references, and the design is perfect, and
> > FreeAndNil is just sitting there doing nothing, that means I would be
> > spending my time badly, trying to see if something that is not broken
> > needs a fix.
> 
> Well, it seems to me you're reading *way* too much into a simple FreeAndNil.
> 

Maybe I am ;-)

Still, I think it is a bad habit using FreeandNil everywhere.

Dalija Prasnikar
0
Dalija
10/17/2010 9:01:17 AM
On 17.10.2010 1:11, Dalija Prasnikar wrote:
> Using FreeAndNil on InnerObject would definitively be abusing FreeAndNil.
> At that point if you still have references to InnerObject that really means that
> you are dealing with badly designed code, and if you don't there is no point in
> calling FreeAndNil because it makes harder to understand what programmer
> wanted to say (write).

Either an outer object allows nilled inner objects or not. Actually 
using Free on an inner object would definitively be abusing Free because 
using Free you somehow expect that the object reference might be nilled. 
In this sense it is not different from FreeAndNil.

Guys you are amazing. You read into FreeAndNil intensively but 
completely ignore Free, although it has its own implications and nuances.
0
Andrew
10/17/2010 10:35:46 AM
On 17.10.2010 15:01, Dalija Prasnikar wrote:
> Still, I think it is a bad habit using FreeandNil everywhere.

I shown (look up the thread) an example of code where FreeAndNil might 
save your a... Could you display a couple of examples where:

1. Using FreeAndNil instead of Free makes things worse than they are.
2. FreeAndNil means a bad design which become the good one by replacing 
FreeAndNil by the call to Free.

Without these examples all that spacious reasonings and condemnations of 
FreeAndNil are worth nothing.
0
Andrew
10/17/2010 10:35:51 AM
> {quote:title=Andrew Fionik wrote:}{quote}
> On 17.10.2010 1:11, Dalija Prasnikar wrote:
> > Using FreeAndNil on InnerObject would definitively be abusing FreeAndNil.
> > At that point if you still have references to InnerObject that really means that
> > you are dealing with badly designed code, and if you don't there is no point in
> > calling FreeAndNil because it makes harder to understand what programmer
> > wanted to say (write).
> 
> Either an outer object allows nilled inner objects or not. Actually 
> using Free on an inner object would definitively be abusing Free because 
> using Free you somehow expect that the object reference might be nilled. 
> In this sense it is not different from FreeAndNil.
> 
> Guys you are amazing. You read into FreeAndNil intensively but 
> completely ignore Free, although it has its own implications and nuances.

In this example I was talking about freeing InnerObject in OuterObject destructor.
No need to FreeAndNil there. 

Dalija Prasnikar
0
Dalija
10/17/2010 5:07:56 PM
> {quote:title=Andrew Fionik wrote:}{quote}
> On 17.10.2010 15:01, Dalija Prasnikar wrote:
> > Still, I think it is a bad habit using FreeandNil everywhere.
> 
> I shown (look up the thread) an example of code where FreeAndNil might 
> save your a... Could you display a couple of examples where:
> 

And how often will you write some obvoius error where FreeAndNil will save your a...?

> 1. Using FreeAndNil instead of Free makes things worse than they are.
> 2. FreeAndNil means a bad design which become the good one by replacing 
> FreeAndNil by the call to Free.
> 

Like I said earlier, in my opinion FreeAndNil obscures the code, making it harder to
understand its meaning. If you are dealing with some bad design with possibilities of 
dangling references, OK go and use FreeAndNil, but the fact is that this design where
you could benefit from FreeAndNil in catching errors is bad.

Bad design cannot be fixed by using Free, no more than it could be fixed using FreeAndNil.
Bad design needs to be redesigned completely. If you have decently designed code
using FreeAndNil would be totaly useless because there would be no errors to catch. And
the obvious errors one coud write in a good design can usually be caught simply by reading 
the code.

> Without these examples all that spacious reasonings and condemnations of 
> FreeAndNil are worth nothing.

That is your opinion and I respect it, also I have my opinion that is different from yours.
Obviously you are not going to change my opinion, and I am not going to change yours.

Dalija Prasnikar
0
Dalija
10/17/2010 5:22:59 PM
Andrew Fionik wrote:

> On 17.10.2010 15:01, Dalija Prasnikar wrote:
> > Still, I think it is a bad habit using FreeandNil everywhere.
> 
> I shown (look up the thread) an example of code where FreeAndNil
> might save your a... Could you display a couple of examples where:
> 
> 1. Using FreeAndNil instead of Free makes things worse than they are.

It usually doesn't, unless the parameter of FreeAndNil is not an object.

> 2. FreeAndNil means a bad design which become the good one by
> replacing FreeAndNil by the call to Free.

No one is claiming such a situation. I don't know about Dalija, but
what I am saying is that if you code following a few simple principles,
you NEVER GET INTO A SITUATION WHERE FREEANDNIL COULD MAKE A
DIFFERENCE. In such a design, FreeAndNil is totally OBSOLETE, even for
debugging purposes.

It is a fact that if I see code with FreeAndNil in it, it is code that
is designed thus that there CAN BE "loose" references to objects (and
FreeAndNil is used to make sure that an Assigned() test or similar will
give a "meaningful" result), and that is, IMO, not good design. It is
certainly not "defensive programming". Defensive programming prevents
such situations.

The main characteristic of a good defensive design is that you always
know, at all times, which references to an object exist, (most of the
time, there should only be one), and that, as long as there is at least
one reference to such an object, it won't be freed.
-- 
Rudy Velthuis (TeamB)        http://www.teamb.com

"Programming today is a race between software engineers striving 
 to build bigger and better idiot-proof programs, and the Universe
 trying to produce bigger and better idiots. So far, the Universe 
 is winning." -- Rich Cook.
0
Rudy
10/17/2010 6:15:05 PM
> {quote:title=Rudy Velthuis (TeamB) wrote:}{quote}
> Andrew Fionik wrote:
> 
> > On 17.10.2010 15:01, Dalija Prasnikar wrote:
> > > Still, I think it is a bad habit using FreeandNil everywhere.
> > 
> > I shown (look up the thread) an example of code where FreeAndNil
> > might save your a... Could you display a couple of examples where:
> > 
> > 1. Using FreeAndNil instead of Free makes things worse than they are.
> 
> It usually doesn't, unless the parameter of FreeAndNil is not an object.
> 
> > 2. FreeAndNil means a bad design which become the good one by
> > replacing FreeAndNil by the call to Free.
> 
> No one is claiming such a situation. I don't know about Dalija, but
> what I am saying is that if you code following a few simple principles,
> you NEVER GET INTO A SITUATION WHERE FREEANDNIL COULD MAKE A
> DIFFERENCE. In such a design, FreeAndNil is totally OBSOLETE, even for
> debugging purposes.
> 
> It is a fact that if I see code with FreeAndNil in it, it is code that
> is designed thus that there CAN BE "loose" references to objects (and
> FreeAndNil is used to make sure that an Assigned() test or similar will
> give a "meaningful" result), and that is, IMO, not good design. It is
> certainly not "defensive programming". Defensive programming prevents
> such situations.
> 
> The main characteristic of a good defensive design is that you always
> know, at all times, which references to an object exist, (most of the
> time, there should only be one), and that, as long as there is at least
> one reference to such an object, it won't be freed.
> -- 

Thank you, Rudy ;-)

Dalija Prasnikar
0
Dalija
10/17/2010 7:11:35 PM
On 17.10.2010 23:07, Dalija Prasnikar wrote:
> In this example I was talking about freeing InnerObject in OuterObject destructor.
> No need to FreeAndNil there.

No need to call Free also, why don't you call the destructor then?
0
Andrew
10/18/2010 1:49:28 AM
On 17.10.2010 23:22, Dalija Prasnikar wrote:
>> I shown (look up the thread) an example of code where FreeAndNil might
>> save your a... Could you display a couple of examples where:

> And how often will you write some obvoius error where FreeAndNil will save your a...?

It happens sometimes. With FreeAndNil an error typically becomes visible 
immediately.

>> 1. Using FreeAndNil instead of Free makes things worse than they are.
>> 2. FreeAndNil means a bad design which become the good one by replacing
>> FreeAndNil by the call to Free.

> Like I said earlier, in my opinion FreeAndNil obscures the code, making it harder to
> understand its meaning. If you are dealing with some bad design with possibilities of
> dangling references, OK go and use FreeAndNil, but the fact is that this design where
> you could benefit from FreeAndNil in catching errors is bad.

An example please. A logical link between a bad design and FreeAndNil 
somehow escapes from me. Can you demonstrate it?

> Bad design cannot be fixed by using Free, no more than it could be fixed using FreeAndNil.
> Bad design needs to be redesigned completely. If you have decently designed code
> using FreeAndNil would be totaly useless because there would be no errors to catch. And
> the obvious errors one coud write in a good design can usually be caught simply by reading
> the code.

:)

>> Without these examples all that spacious reasonings and condemnations of
>> FreeAndNil are worth nothing.
>
> That is your opinion and I respect it, also I have my opinion that is different from yours.
> Obviously you are not going to change my opinion, and I am not going to change yours.
0
Andrew
10/18/2010 1:58:39 AM
On 18.10.2010 0:15, Rudy Velthuis (TeamB) wrote:
>> 1. Using FreeAndNil instead of Free makes things worse than they are.
>
> It usually doesn't, unless the parameter of FreeAndNil is not an object.

I knew you would say it, although I tried to do it and it raised EAV 
immediately right on the place. It is good. However I'd prefer to have 
type inference working in order to write something like:

Discard(TheObject)

instead of

Discard<TMyObject>(TheObject)

>> 2. FreeAndNil means a bad design which become the good one by
>> replacing FreeAndNil by the call to Free.

> No one is claiming such a situation.

Then why are you against of FreeAndNil but not against of FastMM, Free, 
Assert, etc? In a perfect design there is no need for FastMM in 
debugging mode. The situation where filling the used memory with the 
specific pattern could be helpful is impossible in the case of good design.

 > I don't know about Dalija, but
> what I am saying is that if you code following a few simple principles,
> you NEVER GET INTO A SITUATION WHERE FREEANDNIL COULD MAKE A
> DIFFERENCE. In such a design, FreeAndNil is totally OBSOLETE, even for
> debugging purposes.

I wrote an example in which FreeAndNil made a difference. Does it count?

> It is a fact that if I see code with FreeAndNil in it, it is code that
> is designed thus that there CAN BE "loose" references to objects (and
> FreeAndNil is used to make sure that an Assigned() test or similar will
> give a "meaningful" result), and that is, IMO, not good design. It is
> certainly not "defensive programming". Defensive programming prevents
> such situations.  The main characteristic of a good defensive design is that you always
> know, at all times, which references to an object exist, (most of the
> time, there should only be one), and that, as long as there is at least
> one reference to such an object, it won't be freed.

When you'll be writing your set of rules don't forget to supply them 
with examples of good coding and bad coding. Especially when you'll 
touch the FreeAndNil case.
0
Andrew
10/18/2010 2:26:08 AM
> {quote:title=Andrew Fionik wrote:}{quote}
> On 17.10.2010 23:07, Dalija Prasnikar wrote:
> > In this example I was talking about freeing InnerObject in OuterObject destructor.
> > No need to FreeAndNil there.
> 
> No need to call Free also, why don't you call the destructor then?

Because the InnerObject could be nil when OuterObject destructor is called.
If there is an exception raised in the constructor of OuterObject destructor will be 
called for cleanup.

Dalija Prasnikar
0
Dalija
10/18/2010 9:14:23 AM
After all this discussion I looked up the implementations of Free and 
FreeAndNil:

(I am still on Delphi 2007 if that makes any difference)

procedure TObject.Free;
begin
  if Self <> nil then
    Destroy;
end;

procedure FreeAndNil(var Obj);
var
  Temp: TObject;
begin
  Temp := TObject(Obj);
  Pointer(Obj) := nil;
  Temp.Free;
end;

Obviously, if you can use Free at all then you can also use FreeAndNil, the 
only difference being that FreeAndNil operates on a pointer to an object and 
invalidates this pointer before calling Free.

So problems may arise if you have more than one pointer to the same object 
and rely upon pointers to be nil (always using FreeAndNil to destroy the 
object) whenever the object does not exist (i.e. before create and after 
destroy).
0
Sven
10/18/2010 9:28:44 AM
> {quote:title=Andrew Fionik wrote:}{quote}
>
> An example please. A logical link between a bad design and FreeAndNil 
> somehow escapes from me. Can you demonstrate it?
> 

Bad design is a design where you are using FreeAndNil to CATCH ERRORS.
This is simple as that. 

Ok, you can use FreeAndNil to catch error like one in your first example, but
really this error is so obvious that you should catch it just glimpsing over the code.

I would give you an example but I don't have such bad code, and I have other things 
to do than to invent bad designs just to show you. And in the end you would be 
just saying that in my example FreeAndNil saved my a...
Which will be true, but in that case you are dealing with bad design. The whole
point in this discussion is that in bad design FreeAndNil can save your a..., but
only in a bad design.

If you have not understood what I am trying to say in whole this thread, then I 
really have nothing else to say.

Dalija Prasnikar
0
Dalija
10/18/2010 9:29:23 AM
On 18.10.2010 15:14, Dalija Prasnikar wrote:
>> No need to call Free also, why don't you call the destructor then?
>
> *Because the InnerObject could be nil* when OuterObject destructor is called.
> If there is an exception raised in the constructor of OuterObject destructor will be
> called for cleanup.

So could write it in the following way:

if InnerObject<>nil then InnerObject.Destroy;

Everything is perfectly clear in this code. But according to your logic, 
"calling FreeAndNil makes it harder to understand what programmer wanted 
to say (write)" but calling Free doesn't make it hard to understand 
though two routines essenitally do the same.

Ok. We use FreeAndNil for what its name says - to free an object and to 
nil a reference to it. You say that it is "hard to understand what 
programmer wanted to say". So calling FreeAndNil could have meanings 
other than "Free and nil". Right? What are they?
0
Andrew
10/18/2010 10:39:58 AM
On 18.10.2010 15:29, Dalija Prasnikar wrote:
> Bad design is a design where you are using FreeAndNil to CATCH ERRORS.
> This is simple as that.
>
> Ok, you can use FreeAndNil to catch error like one in your first example, but
> really this error is so obvious that you should catch it just glimpsing over the code.

The code might be ten to hundred times more. I doubt that anyone is able 
to see such an error just glimpsing over the code.

> I would give you an example but I don't have such bad code, and I have other things
> to do than to invent bad designs just to show you. And in the end you would be
> just saying that in my example FreeAndNil saved my a...
> Which will be true, but in that case you are dealing with bad design. The whole
> point in this discussion is that in bad design FreeAndNil can save your a..., but
> only in a bad design.
> If you have not understood what I am trying to say in whole this thread, then I
> really have nothing else to say.

No more questions. But when you encounter an example of bad design where 
FreeAndNil is a clear sign and key part of "badness" please don't 
hesitate to post it here.
0
Andrew
10/18/2010 10:50:07 AM
Andrew Fionik wrote:

> On 18.10.2010 0:15, Rudy Velthuis (TeamB) wrote:
> >> 1. Using FreeAndNil instead of Free makes things worse than they
> are.
> > 
> > It usually doesn't, unless the parameter of FreeAndNil is not an
> > object.
> 
> I knew you would say it, although I tried to do it and it raised EAV 
> immediately right on the place. It is good. However I'd prefer to
> have type inference working in order to write something like:
> 
> Discard(TheObject)
> 
> instead of
> 
> Discard<TMyObject>(TheObject)

Not sure how that is related to the issue at hand.
> 
> >> 2. FreeAndNil means a bad design which become the good one by
> >> replacing FreeAndNil by the call to Free.
> 
> > No one is claiming such a situation.
> 
> Then why are you against of FreeAndNil

I am not AGAINST it, I am merely saying that if the code is written
properly, it is OBSOLETE.


> but not against of FastMM,
> Free, Assert, etc?

Wow. Now you are really packing a lot of unrelated things together.
Assert does more than just check for nil, it also checks if values have
wrong values. Now, there are also ways to avoid such situations, but it
may be harder. My code doesn't use many Asserts (come to think of it,
none), and I usually only need FastMM to find problems in code that is
not mine. And well, yes, of course I need Free.
 
> > I don't know about Dalija, but
> > what I am saying is that if you code following a few simple
> > principles, you NEVER GET INTO A SITUATION WHERE FREEANDNIL COULD
> > MAKE A DIFFERENCE. In such a design, FreeAndNil is totally
> > OBSOLETE, even for debugging purposes.
> 
> I wrote an example in which FreeAndNil made a difference. Does it
> count?

If it makes a difference, I'd say the overall design of the code should
be reconsidered (IOW, no, it doesn't count). Such a situation should
never arise. I am trying to tell you this, and you keep on coming with
situations where it makes a difference. I have the impression you don't
understand what I am saying.

As I said before, the possiblity of getting into a bar brawl is pretty
close to zero if you never go into a bar. So if you completely avoid
situations where there can be "loose" references to freed objects, the
possibility that a freed object is accessed by accident, or the
necessity for the place of access to check for nil, is zero too, so
FreeAndNil CAN'T make a difference. One should always know (and be able
to easily tell) which references to an object exist, and objects should
not be freed before the last reference becomes obsolete.

-- 
Rudy Velthuis (TeamB)        http://www.teamb.com

"Always remember you are a totally unique individual; just like
 everyone else."
 -- Unknown
0
Rudy
10/18/2010 11:23:20 AM
"Andrew Fionik"  wrote
.....................
> So could write it in the following way:
>
> if InnerObject<>nil then InnerObject.Destroy;

That is precisely what InnerObject.Free does

> Everything is perfectly clear in this code. But according to your logic,
> "calling FreeAndNil makes it harder to understand what programmer wanted
> to say (write)" but calling Free doesn't make it hard to understand
> though two routines essenitally do the same.
>
> Ok. We use FreeAndNil for what its name says - to free an object and to
> nil a reference to it. You say that it is "hard to understand what
> programmer wanted to say". So calling FreeAndNil could have meanings
> other than "Free and nil". Right? What are they?

There is no difference unless you have more than one pointer reference to it 
because FreeAndNil can only invalidate one of the pointers.
0
Sven
10/18/2010 11:24:25 AM
Andrew Fionik wrote:

> On 17.10.2010 23:07, Dalija Prasnikar wrote:
> > In this example I was talking about freeing InnerObject in
> > OuterObject destructor.  No need to FreeAndNil there.
> 
> No need to call Free also, why don't you call the destructor then?

Your forgot what happens when a constructor fails and the object is
only partly constructed.

If a constructor fails, the destructor is called. So if the constructor
of OuterObject fails, its destructor is called. When that happens,
InnerObject my not be constructed yet (in which case it will be nil),
so the OuterObject destructor should use Free (which checks for nil) to
discard the InnerObject.

IOW, the reason to use Free is a totally different one than the reason
to use FreeAndNil. Using FreeAndNil in a destructor is pure nonsense,
unless your code is so incredibly convoluted that you might try to
access an object a few lines after you destroyed it (and in that case,
the use of FreeAndNil or not is the least of your worries <g>).
-- 
Rudy Velthuis (TeamB)        http://www.teamb.com

"When his life was ruined, his family killed, his farm 
 destroyed, Job knelt down on the ground and yelled up to the 
 heavens, 'Why god? Why me?' and the thundering voice of God 
 answered, 'There's just something about you that pisses me 
 off.'" -- Stephen King.
0
Rudy
10/18/2010 11:31:45 AM
Andrew Fionik wrote:

> So could write it in the following way:
> 
> if InnerObject<>nil then InnerObject.Destroy;

Yes, you could. But for that, there is Free, which already does that,
for all classes. Using Free (always, consistently, without exception)
is less error prone than always to code the condition and call the
destructor.
-- 
Rudy Velthuis (TeamB)        http://www.teamb.com

"The most important job is not to be Governor, or First Lady in 
 my case." -- George W. Bush
0
Rudy
10/18/2010 11:36:11 AM
Andrew Fionik wrote:

> So could write it in the following way:
> 
> if InnerObject<>nil then InnerObject.Destroy;
> 
> Everything is perfectly clear in this code. But according to your
> logic, "calling FreeAndNil makes it harder to understand what
> programmer wanted to say (write)" but calling Free doesn't make it
> hard to understand though two routines essenitally do the same.

Oh no. They don't do the same at all. You already described the
difference:
 
> Ok. We use FreeAndNil for what its name says - to free an object and
> to nil a reference to it.

FreeAndNil additionally NILS THE REFERENCE. 

But nilling the reference only makes sense if there is a possibility
that the reference is accessed AFTER it was freed. If that possiblity
exists, the object should not have been freed yet.

So if someone tells me that code only runs properly with FreeAndNil,
that means that objects are freed although they can still be accessed.
That is a sign of bad design, IMO.

So yes, you can use FreeAndNil where you would use Free, but WHY? It is
obsolete in 99.9% of the cases (even for debugging purposes) and it is
not type safe. Free is to be preferred.

-- 
Rudy Velthuis (TeamB)        http://www.teamb.com

"Beware of bugs in the above code; I have only proved it correct,
 not tried it." -- Donald Knuth
0
Rudy
10/18/2010 11:46:14 AM
Sven Pran wrote:

> So problems may arise if you have more than one pointer to the same
> object and rely upon pointers to be nil (always using FreeAndNil to
> destroy the object) whenever the object does not exist (i.e. before
> create and after destroy).

Note that FreeAndNil only nils ONE reference. Any additional references
are not nilled out. Such is a sign of extremely bad design, IMO. If
more than one reference exist, the object should not be freed yet.

-- 
Rudy Velthuis (TeamB)        http://www.teamb.com

"Do you love your Creator? Love your fellow beings first."
 -- Prophet Muhammad
0
Rudy
10/18/2010 11:49:09 AM
Andrew Fionik wrote:

> An example please. A logical link between a bad design and FreeAndNil 
> somehow escapes from me. Can you demonstrate it?

Code that relies on FreeAndNil relies on the fact that objects may be
accessed after they were destroyed. That is bad design. Don't you agree?

It is my experience that 
1. most of the code that uses FreeAndNil is code from people who do not
know exactly which references to an object might still exist when it is
freed. IOW, code that may have dangling references.
2. Others use it as some kind of misunderstood "defensive programming".
3. Yet others think that if they use FreeAndNil, they are freeing the
object and nilling all references to it.

Sure, you can use FreeAndNil everywhere others would simply use Free,
but WHY? It is, assuming decent design, in 99.9% of the cases nonsense
to nil out a reference after the object was freed. Additionally,
FreeAndNil is not type safe.

-- 
Rudy Velthuis (TeamB)        http://www.teamb.com

"Rarely is the question asked: Is our children learning?"
 -- George W. Bush
0
Rudy
10/18/2010 12:01:36 PM
> {quote:title=Andrew Fionik wrote:}{quote}
> On 18.10.2010 15:29, Dalija Prasnikar wrote:
> > Bad design is a design where you are using FreeAndNil to CATCH ERRORS.
> > This is simple as that.
> >
> > Ok, you can use FreeAndNil to catch error like one in your first example, but
> > really this error is so obvious that you should catch it just glimpsing over the code.
> 
> The code might be ten to hundred times more. I doubt that anyone is able 
> to see such an error just glimpsing over the code.
> 

If you have procedure that spans ove hundreds of lines is also a sign of bad design.

> > I would give you an example but I don't have such bad code, and I have other things
> > to do than to invent bad designs just to show you. And in the end you would be
> > just saying that in my example FreeAndNil saved my a...
> > Which will be true, but in that case you are dealing with bad design. The whole
> > point in this discussion is that in bad design FreeAndNil can save your a..., but
> > only in a bad design.
> > If you have not understood what I am trying to say in whole this thread, then I
> > really have nothing else to say.
> 
> No more questions. But when you encounter an example of bad design where 
> FreeAndNil is a clear sign and key part of "badness" please don't 
> hesitate to post it here.

No problem.

Dalija Prasnikar
0
Dalija
10/18/2010 12:04:57 PM
Rob McDonell wrote:

> On 17/10/2010 6:22 AM, Dalija Prasnikar wrote:
> > This is not the question I had in mind. If I see such code I wonder
> > if there are dangling references to this object, and if there are
> > then the design is bad and if design is bad, who knows what else is
> > not right with this code.  And if there are no dangling references,
> > and the design is perfect, and FreeAndNil is just sitting there
> > doing nothing, that means I would be spending my time badly, trying
> > to see if something that is not broken needs a fix.
> 
> Well, it seems to me you're reading way too much into a simple
> FreeAndNil.

It is my experience that FreeAndNil is almost always a sign of bad
design with dangling references. That is certainly not reading way too
much into it.
-- 
Rudy Velthuis (TeamB)        http://www.teamb.com

"The great thing about a computer notebook is that no matter how 
 much you stuff into it, it doesn't get bigger or heavier." 
 -- Bill Gates.
0
Rudy
10/18/2010 12:08:39 PM
"Rudy Velthuis (TeamB)" wrote
> Sven Pran wrote:
>
>> So problems may arise if you have more than one pointer to the same
>> object and rely upon pointers to be nil (always using FreeAndNil to
>> destroy the object) whenever the object does not exist (i.e. before
>> create and after destroy).
>
> Note that FreeAndNil only nils ONE reference. Any additional references
> are not nilled out.

I have a strange feeling that this is precisely what I expressed?

Such is a sign of extremely bad design, IMO. If
> more than one reference exist, the object should not be freed yet.

Precisely.

But I have had applications where a particular object can be needed for 
shorter periods during my application or not necessarily at all. If I don't 
initially know all parameters required for the creation of TObject until it 
is needed then it can be very convenient to have:

if PObject = nil then PObject := TObject.Create;

and use FreeAndNil(PObject) to clean up when I am done and maybe is about to 
continue my application with an entirely different dataspace.

The effect is that I use PObject as a semaphore to indicate if the Object 
instance has already been created.
0
Sven
10/18/2010 3:17:16 PM
On 18.10.2010 18:01, Rudy Velthuis (TeamB) wrote:
> Code that relies on FreeAndNil relies on the fact that objects may be
> accessed after they were destroyed. That is bad design. Don't you agree?

I agree that if objects are accessed after they were destroyed is bad 
design. However I don't agree with that logical link between FreeAndNil 
and the possibility of access after destruction.

Ok. The freed objects cannot be accessed by design. Because my design is 
good and I (just like you and any other developer) do the best to 
prevent them from being accessed.

The difference is that I think even if I'm sure that my design is good, 
even if I make tests, there is still a chance of an error or misuse or 
unpredictable programming path which was not expected. Because humans 
are not perfect. Because if it can go wrong it will. Because even if you 
think that it can't go wrong because of your perfect design, it still 
can. I admit it. It seems you don't.

> It is my experience that
> 1. most of the code that uses FreeAndNil is code from people who do not
> know exactly which references to an object might still exist when it is
> freed. IOW, code that may have dangling references.

When you hold a reference to an object which is also accessible from 
outside (declared in a public secion) do you always use the observer 
pattern? If you don't then you are among these people, because you only 
think that you know which references to an object might still exist.

The only difference you don't use FreeAndNil but it doesn't matter.

> 2. Others use it as some kind of misunderstood "defensive programming".

If it helps to catch errors then it is "defensive programming". If it 
doesn't then it isn't.

> 3. Yet others think that if they use FreeAndNil, they are freeing the
> object and nilling all references to it.

Some think that if they use Free they are freeing object and nilling all 
references to it. It doesn't make Free bad.

> Sure, you can use FreeAndNil everywhere others would simply use Free,
> but WHY? It is, assuming decent design, in 99.9% of the cases nonsense
> to nil out a reference after the object was freed.

Because it helps, especially with accidental and unwanted errors. 
Another one example from the real world.

A:=TMyAObject.Create;
try
   B:=TMyBObject.Create;
   try
     DoSomething(A, B);
   finally
     B.Free;
   end;
   LogTheData(A);
   if VerboseLogging then
     LogTheHugeChunkOfDataAndConsumeAlotOfCPU(A, C, D, E, F);
finally
   A.Free;
end;

Then months later I decide to include some data from B into the logging. 
Unfortunately I was not too accurate and forgot to move the appropriate 
code.

A:=TMyAObject.Create;
try
   B:=TMyBObject.Create;
   try
     DoSomething(A, B);
   finally
     B.Free;
   end;
   LogTheData(A);
   if VerboseLogging then
     LogTheHugeChunkOfDataAndConsumeAlotOfCPU(A, B, C, D, E, F);
finally
   A.Free;
end;

The position of the LogTheData is wrong. I wouldn't call it a bad 
design, I would call it coding error. Somehow it works during the test 
run. I may even have a dUnit test for LogData and LogTheHuge. It works 
also. And then happens on another side of the planet.

The correct variant would be below, but I didn't code it, because I 
forgot, tired, was in a hurry, etc.

A:=TMyAObject.Create;
try
   B:=TMyBObject.Create;
   try
     DoSomething(A, B);
     LogTheData(A);
     if VerboseLogging then
       LogTheHugeChunkOfDataAndConsumeAlotOfCPU(A, B, C, D, E, F);
   finally
     B.Free;
   end;
finally
   A.Free;
end;

Oh... no... Such things can happen only with me. Others who simply use 
Free never do such errors. They always accurate. They are never in a 
hurry. Their memory is perfect and they don't forget anything. They can 
read out 99.99% of error by simply looking at the code.

> Additionally, FreeAndNil is not type safe.

Unfortunately. Hopefully they'll improve generics.

If you are still disagree with me I can live with it. I will not dicuss 
this question anymore because I have nothing else to say.
0
Andrew
10/18/2010 3:28:13 PM
> There is also a third category. You should not use FreeAndNil in destructors

A grep search in my BDS 2006\source directory gave me *1120 matches of FreeAndNil*. I could not count them all, but 95% of the occurrences I saw were in destructors.

I don't have Delphi XE, but I guess most VCL source code remains. 

The important thing in Allen's blog was: "The problem with that is that many seem to use FreeAndNil as some magic bullet that will slay that mysterious crash dragon". 
I read that as: If your code is crashing using +SomeInstance.Free+, and the bug goes away using +FreeAndNil(SomeInstance)+, then you have a design problem.

Best regards
0
Alexandre
10/18/2010 4:18:10 PM
Andrew Fionik wrote:

> > Ok, you can use FreeAndNil to catch error like one in your first
> > example, but really this error is so obvious that you should catch
> > it just glimpsing over the code.
> 
> The code might be ten to hundred times more. I doubt that anyone is
> able to see such an error just glimpsing over the code.

Probably not. That is why such code should be redesigned, as I have
said numerous times already. A proper redesign will completely avoid
the situation where such an error is possible.
-- 
Rudy Velthuis (TeamB)        http://www.teamb.com

"Heaven is an American salary, a Chinese cook, an English house, 
 and a Japanese wife. Hell is defined as having a Chinese salary,
 an English cook, a Japanese house, and an American wife."
 -- James H. Kabbler III.
0
Rudy
10/18/2010 9:21:05 PM
Sven Pran wrote:

> The effect is that I use PObject as a semaphore to indicate if the
> Object instance has already been created.

Hmmm... a semaphore that may cause a memory leak. Nothing for me, sorry.

-- 
Rudy Velthuis (TeamB)        http://www.teamb.com

"He had delusions of adequacy." -- Walter Kerr
0
Rudy
10/18/2010 9:48:34 PM
Andrew Fionik wrote:

> On 18.10.2010 18:01, Rudy Velthuis (TeamB) wrote:
> > Code that relies on FreeAndNil relies on the fact that objects may
> > be accessed after they were destroyed. That is bad design. Don't
> > you agree?
> 
> I agree that if objects are accessed after they were destroyed is bad 
> design. However I don't agree with that logical link between
> FreeAndNil and the possibility of access after destruction.

No logical link. Just the observation that code with FreeAndNil often
tends to be badly designed, and that the FreeAndNil is used for various
reasons, all of which would be obsolete if the code were properly
designed.

IOW, properly designed code hardly ever NEEDs FreeAndNil (not even for
debugging purposes). So why should someone use it? Most of the code I
have seen using FreeAndNil actually needed it, and in such cases, it is
a sure sign of bad design.

-- 
Rudy Velthuis (TeamB)        http://www.teamb.com

"He can compress the most words into the smallest idea of any man 
 I know." -- Abraham Lincoln
0
Rudy
10/18/2010 9:53:02 PM
Andrew Fionik wrote:

> The difference is that I think even if I'm sure that my design is
> good, even if I make tests, there is still a chance of an error or
> misuse or unpredictable programming path which was not expected.

Er... no. That chance can be completely avoided (assuming that any
third party code used is properly designed as well).
-- 
Rudy Velthuis (TeamB)        http://www.teamb.com

"Philosophers have merely interpreted the world. The point is
 to change it."
 -- Karl Marx
0
Rudy
10/18/2010 9:55:07 PM
Andrew Fionik wrote:

> On 18.10.2010 18:01, Rudy Velthuis (TeamB) wrote:
> > Code that relies on FreeAndNil relies on the fact that objects may
> > be accessed after they were destroyed. That is bad design. Don't
> > you agree?
> 
> I agree that if objects are accessed after they were destroyed is bad 
> design. However I don't agree with that logical link between
> FreeAndNil and the possibility of access after destruction.
> 
> Ok. The freed objects cannot be accessed by design. Because my design
> is good and I (just like you and any other developer) do the best to 
> prevent them from being accessed.
> 
> The difference is that I think even if I'm sure that my design is
> good, even if I make tests, there is still a chance of an error or
> misuse or unpredictable programming path which was not expected.
> Because humans are not perfect. Because if it can go wrong it will.

I certainly make mistakes too. But the mistakes FreeAndNil could
prevent can't be made if the code is designed properly (and that is not
too hard, actually, once you get the hang of it). IOW, proper codes
doesn't need FreeAndNil to catch dangling references.

> Because even if you think that it can't go wrong because of your
> perfect design, it still can. I admit it. It seems you don't.

Things can't go wrong, sure, but if I don't have more than one
reference, there can be no dangling one. If I have more than one, I
know exactly, at any time, where they are and how long they will exist
and I won't free the object before the other references are gone. It is
that simple. And if I follow those simple rules, I don't need
FreeAndNil (I'm not quite sure how FreeAndNil could be of any value
with dangling references anyway).
 
> > It is my experience that
> > 1. most of the code that uses FreeAndNil is code from people who do
> > not know exactly which references to an object might still exist
> > when it is freed. IOW, code that may have dangling references.
> 
> When you hold a reference to an object which is also accessible from 
> outside (declared in a public secion) do you always use the observer 
> pattern?

Not sure what you mean. If, for instance, I write a component that
exposes a TFont object, and some idiot using my component actually
frees the font and things go haywire, that is not my responsibility
anymore. I won't try to write code to avoid such actions (it is nigh
impossible anyway).

> If you don't then you are among these people, because you
> only think that you know which references to an object might still
> exist.

I am responsible for my code, not for the code of others. 

> > 2. Others use it as some kind of misunderstood "defensive
> > programming".
> 
> If it helps to catch errors then it is "defensive programming". If it 
> doesn't then it isn't.

If the code is designed properly, the errors it could help catch can't
happen. If it is actually needed to catch errors, the design is er...
suboptimal.
> 
> > 3. Yet others think that if they use FreeAndNil, they are freeing
> > the object and nilling all references to it.
> 
> Some think that if they use Free they are freeing object and nilling
> all references to it.

Oh? Then they missed one of the most basic basics of Delphi
programming. <shrug>

-- 
Rudy Velthuis (TeamB)        http://www.teamb.com

"Violence is the last refuge of the incompetent." -- Issac Asimov
0
Rudy
10/18/2010 10:11:42 PM
"Rudy Velthuis (TeamB)"  wrote
> Sven Pran wrote:
>
>> The effect is that I use PObject as a semaphore to indicate if the
>> Object instance has already been created.
>
> Hmmm... a semaphore that may cause a memory leak. Nothing for me, sorry.

How?

I ensure PObject is nil during FormCreate and that the only calls which can 
modify PObject are
FreeAndNil(PObject);
and
if PObject = nil then PObject := TObject.Create;

Aside from that PObject is readonly.

So how can this use of PObject cause a memory leak?
0
Sven
10/18/2010 10:14:21 PM
Andrew Fionik wrote:

> A:=TMyAObject.Create;
> try
>    B:=TMyBObject.Create;
>    try
>      DoSomething(A, B);
>    finally
>      B.Free;
>    end;
>    LogTheData(A);
>    if VerboseLogging then
>      LogTheHugeChunkOfDataAndConsumeAlotOfCPU(A, B, C, D, E, F);
> finally
>    A.Free;
> end;

Well, sorry that this happens to you, but using a reference to a freed
object a few lines after it was freed is something you shouldn't do,
indeed. What shall I say?

-- 
Rudy Velthuis (TeamB)        http://www.teamb.com

"Patriotism is the last refuge of a scoundrel."
 -- Samuel Johnson, English lexicographer, to which Ambrose
 Bierce replied: ‘I beg to submit that it is the first.’
0
Rudy
10/18/2010 10:20:18 PM
Sven Pran wrote:

> "Rudy Velthuis (TeamB)"  wrote
> > Sven Pran wrote:
> > 
> >> The effect is that I use PObject as a semaphore to indicate if the
> >> Object instance has already been created.
> > 
> > Hmmm... a semaphore that may cause a memory leak. Nothing for me,
> > sorry.
> 
> How?
> 
> I ensure PObject is nil during FormCreate and that the only calls
> which can modify PObject are
> FreeAndNil(PObject);
> and
> if PObject = nil then PObject := TObject.Create;
> 
> Aside from that PObject is readonly.
> 
> So how can this use of PObject cause a memory leak?

You could forget to call FreeAndNil or Free on the object. Why not
simply a Boolean that doesn't need to be freed explicitly?

-- 
Rudy Velthuis (TeamB)        http://www.teamb.com

"In the 1980s capitalism triumphed over communism. In the 1990s
 it triumphed over democracy."
 -- David Korten
0
Rudy
10/18/2010 10:23:24 PM
On 19.10.2010 4:20, Rudy Velthuis (TeamB) wrote:
> Well, sorry that this happens to you, but using a reference to a freed
> object a few lines after it was freed is something you shouldn't do,
> indeed. What shall I say?

You should say: "With FreeAndNil you would notice the error 
immediately", but you won't say it because FreeAndNil is a taboo word. :)
0
Andrew
10/19/2010 1:38:47 AM
> {quote:title=Rudy Velthuis (TeamB) wrote:}{quote}
> Sven Pran wrote:
> 
> > "Rudy Velthuis (TeamB)"  wrote
> > > Sven Pran wrote:
> > > 
> > >> The effect is that I use PObject as a semaphore to indicate if the
> > >> Object instance has already been created.
> > > 
> > > Hmmm... a semaphore that may cause a memory leak. Nothing for me,
> > > sorry.
> > 
> > How?
> > 
> > I ensure PObject is nil during FormCreate and that the only calls
> > which can modify PObject are
> > FreeAndNil(PObject);
> > and
> > if PObject = nil then PObject := TObject.Create;
> > 
> > Aside from that PObject is readonly.
> > 
> > So how can this use of PObject cause a memory leak?
> 
> You could forget to call FreeAndNil or Free on the object. Why not
> simply a Boolean that doesn't need to be freed explicitly?
> 

Sorry Rudy, but this one is legitimate use of FreeAndNil. Just freeing the object
won't  solve memory leak problems. You have to design this kind of things
well also. Introducing the boolean just increases a chance of error. And why
should you introduce boolean when you have perfectly valid value of an
object variable and that is nil if it is not created.

FreeAndNil is not totally obsolete, it is useful, just not for those things others
claim (like catching errors).

Dalija Prasnikar
0
Dalija
10/19/2010 8:01:56 AM
Andrew Fionik wrote:

> On 19.10.2010 4:20, Rudy Velthuis (TeamB) wrote:
> > Well, sorry that this happens to you, but using a reference to a
> > freed object a few lines after it was freed is something you
> > shouldn't do, indeed. What shall I say?
> 
> You should say: "With FreeAndNil you would notice the error 
> immediately", but you won't say it because FreeAndNil is a taboo
> word. :)

If you can think about using FreeAndNil, you can think about when the
object should be freed. Sorry, but using FreeAndNil to prevent an error
in the next few lines of the same method is, IMO, silly.

-- 
Rudy Velthuis (TeamB)        http://www.teamb.com

"Defining and analyzing humor is a pastime of humorless people."
 -- Robert Benchley (1889 - 1945)
0
Rudy
10/19/2010 11:14:13 AM
> If you did have a serious look at that thread you should know it wasn't
> just about merely zeroing all memory (although this was what the OP
> might be referring too in his OP, it doesn't appear to be his end-goal).
>
> To me this discussion "ended" that it needs some adjustments/changes in
> the RTL and some serious debugging/profiling.

Yes it ended but from my point of view there is nothing serious to do,
eventually you have also read my post there that one could use allocMem
instead of Getmem to avoid the Fillchar statement.
Also there was the discussion about prezeroing everything or do it yourself.

But again it's nothing serious from my pov.

>
> IOW this discussion was not about the (ab)use of FreeAndNil.

yes I know I used it just for comparison. Sorry to say but this 
discussion is a bit too emotional for this tiny problem.

For me FreeAndNil is just another function in the RTL one may use it or 
not - but be aware no function whatsoever will prevent you from errors 
you made yourself and no matter what you do sometime the errors pops up
where you at least expect it (using FreeAndNil or not).
0
Michael
10/19/2010 12:12:10 PM
On Mon, 18 Oct 2010 13:08:39 +0100, Rudy Velthuis
<[email protected]> wrote:

>> Well, it seems to me you're reading way too much into a simple
>> FreeAndNil.
>
> It is my experience that FreeAndNil is almost always a sign of bad
> design with dangling references. That is certainly not reading way too
> much into it.

Careful, Rudy. You are letting confirmation bias interfere with your  
logical reasoning.

"Bad design" is "bad design" - Full Stop.

Yes, the design /should/ be perfect and, yes, the programmer(s) /should/  
implement the design correctly and, no, the programmer /should/ not  
dereference a pointer after its memory has been deallocated, but you seem  
to consistently overlook the fact that all the actors in this scenario are  
human and thus all-too-prone to error. So even the most perfect design can  
still be implemented less than optimally.

(You also seem to neglect the complexity problems of large projects with  
multiple units and multiple programmers which must be modified to cater  
for new requirements over long periods of time. No matter how desirable,  
sometimes in the real world there is neither the time nor the money to  
"redesign")

I suggest that readers take a moment to Google for "programming human  
error" and reflect on some of those 8+ MILLION references. Although some  
of the most extensive and authoritative research papers from CACM, SP+E,  
etc lie behind paywalls, there should be enough there to give any  
open-minded reader plenty to think about.

To save a little time, I'll quote from just one summary:   
http://panko.shidler.hawaii.edu/HumanErr/

"... there are errors in about 2% to 5% of all lines of code. Of course  
there are differences based on programming language, program complexity,  
and other factors; but the range is still fairly small."
....
"Note that programmers are not being sloppy. Even with very careful  
development, there will be a fair number of errors."

Remember that these (frightening) error rates come from formal studies -  
not anecdotal evidence from individuals, no matter how esteemed.


Failing to recognise human fallibility (sometimes termed "Hope-Driven  
Development") risks the consequences of Gilb's Second Law:

Gilb's Laws of Unreliability:
1. Computers are unreliable, but humans are even more unreliable.
2. Any system which depends on human reliability is unreliable.

Being aware of those laws (and my own occasional lapses from perfection) I  
try to use coding patterns which reduce the occurrence of common  
programming errors and/or increase the chances of their detection during  
testing. In particular, I always NIL pointers after deallocating memory.

As I've asked before: In exactly which parallel universe could that  
considered a "bad" practice and leaving a dangling pointer to deallocated  
memory considered "good"?

-- 
Paul Scott
Information Management Systems
Macclesfield, UK
0
Paul
10/19/2010 12:37:08 PM
Paul Scott wrote:

> On Mon, 18 Oct 2010 13:08:39 +0100, Rudy Velthuis
> <[email protected]> wrote:
> 
> >> Well, it seems to me you're reading way too much into a simple
> >> FreeAndNil.
> > 
> > It is my experience that FreeAndNil is almost always a sign of bad
> > design with dangling references. That is certainly not reading way
> > too much into it.
> 
> Careful, Rudy. You are letting confirmation bias interfere with your  
> logical reasoning.
 
No, I am not. <sigh>

> "Bad design" is "bad design" - Full Stop.

Not really. There are many grades of bad design. It is not a boolean
thing.
 
> Yes, the design should be perfect and, yes, the programmer(s) should  
> implement the design correctly and, no, the programmer should not  
> dereference a pointer after its memory has been deallocated, but you
> seem to consistently overlook the fact that all the actors in this
> scenario are human and thus all-too-prone to error. So even the most
> perfect design can still be implemented less than optimally.

You know wha? I am human too (I know that some here think I am a bot
<g>), and I make mistakes too. But avoiding situations where such
things can happen has one big advantage: they simply don't happen. I
can make a lot of mistakes, but since I generally avoid situations
where dangling references can happen, they simply don't because they
can't - Full stop.

Now, even in my code, there are situations where they could happen. In
such cases, I try to pack all of it in a class that handles the access
and program very carefully. In the case someone presented with a
treeview holding pointers to objects stored in a tree, I would take
great care that the tree was instantiated early and freed well after
the treeview was freed, so that the items in the treeview could never
point to a freed item. Deleted items in the tree would automatically
result in deletions in the treeview, and vice versa. All this would be
governed by carefully written code in one class taking care of all the
bookkeeping.

But I would probably choose a totally different approach that would not
need references to the objects to be stored in the treeview at all.
That is what I mean with design: the choice of data types and how they
interact, before I start writing code. I try to avoid situations like
the above.

That is how I avoid mistakes. FreeAndNil doesn't play a role anywhere.

-- 
Rudy Velthuis (TeamB)        http://www.teamb.com

"One of the symptoms of an approaching nervous breakdown is the 
 belief that one's work is terribly important."
 -- Bertrand Russell (1872-1970)
0
Rudy
10/20/2010 9:53:15 PM
Rudy,

| There are many grades of bad design. It is not a boolean
| thing.

Yep.  And as I tack-on things to old code that once seemed like "good
design" it seems to go bad and then from bad to worse design.  ;-)

-- 

   Q

10/20/2010 16:24:04

XanaNews Version 1.19.1.278  [Q'sBrokenToolBar]
0
Quentin
10/20/2010 11:25:42 PM
Michael Rabatscher wrote:

> > If you did have a serious look at that thread you should know it
> > wasn't just about merely zeroing all memory (although this was what
> > the OP might be referring too in his OP, it doesn't appear to be
> > his end-goal).
> > 
> > To me this discussion "ended" that it needs some
> > adjustments/changes in the RTL and some serious debugging/profiling.
> 
> Yes it ended but from my point of view there is nothing serious to do,
> eventually you have also read my post there that one could use
> allocMem instead of Getmem to avoid the Fillchar statement.
> Also there was the discussion about prezeroing everything or do it
> yourself.
> 
> But again it's nothing serious from my pov.

It made me curious if a pre-zeroing thread would be helpful especially
when using mainly TObject descendants which requires the allocated
memory to be zeroed. I can think of some situations where it
most-likely will help, but I'm not sure if this will work as a somewhat
more general solution, that would require some RTL changes and some
serious profiling.
 
> > IOW this discussion was not about the (ab)use of FreeAndNil.
> 
> yes I know I used it just for comparison. Sorry to say but this 
> discussion is a bit too emotional for this tiny problem.

Emotional? EMOTIONAL!?!?!?  oh ok, maybe, just a little ;-)
 
> For me FreeAndNil is just another function in the RTL one may use it
> or not - but be aware no function whatsoever will prevent you from
> errors you made yourself and no matter what you do sometime the
> errors pops up where you at least expect it (using FreeAndNil or not).

IIRC this was the whole purpose of the original discussion about using
FreeAndNil. It's not a magic function, it can be used for certain
purposes (f.i. something like a semaphore), but it was about (ab)using
it to fix certain problems, or more over, some recommending it to use
it in less obvious code locations (like destructors) and therefor
hiding a bad code design (and I'm not talking about the more obvious
coding errors some are discussing here in more recent threads).

And to answer somebody else's question:
1) whenever I see a useless FreeAndNil on local procedure / function /
method object variable I do start to wonder about the programming
skills of the author.

2) In other situations: whenever I see a FreeAndNil it makes me wonder
why it used.

3) Just using Free is (or should be) the one and only recommended way
of freeing objects (and in some cases interfaces and/or records). Those
who are arguing that one could as well use Destroy in certain
circumstances should really check out all available Free methods of all
stock TObject descendants before saying so.

-- 
Pieter

Boren's First Law: When in doubt, mumble.
0
Pieter
10/20/2010 11:40:11 PM
On 19.10.2010 18:37, Paul Scott wrote:
> As I've asked before: In exactly which parallel universe could that
> considered a "bad" practice and leaving a dangling pointer to deallocated
> memory considered "good"?

The whole thread turned into an argument.

- FreeAndNil is useful for catching errors.
- Well... yeah... just don't make errors and you don't need FreeAndNil.

:)
0
Andrew
10/21/2010 2:52:50 AM
Pieter Zijlstra wrote:

> it was about (ab)using
> it to fix certain problems, or more over, some recommending it to use
> it in less obvious code locations (like destructors) and therefor
> hiding a bad code design (and I'm not talking about the more obvious
> coding errors some are discussing here in more recent threads).

In my experience, using FreeAndNil helps FIND bad code (access to already freed
objects) instead of hiding it by causing an AV instead of accessing memory
(usually without causing an exception) which (especially in multi-threaded
applications) is already in use for something else, causing a seemingly totally
unrelated crash sometime later.

> 3) Just using Free is (or should be) the one and only recommended way
> of freeing objects (and in some cases interfaces and/or records). Those
> who are arguing that one could as well use Destroy in certain
> circumstances should really check out all available Free methods of all
> stock TObject descendants before saying so.

Free is not virtual. Free should never be overridden as there is no guarantee
that it will ever be called. e.g. if you use FreeAndNil any overridden Free
wouldn't be called. As such I don't think you ever need to worry about someone
overriding Free.
0
Thorsten
10/21/2010 3:10:29 AM
> - FreeAndNil is useful for catching errors.
> - Well... yeah... just don't make errors and you don't need FreeAndNil.

LOL! I rather stay in the camp that admits to make erros and use FreeAndNil. I
seriously don't give a damn about the few cycles more, about some people
thinking it's bad design or even bad code. To be perfectly honest for *ME*
it's bad design to free an instance and leave the variable pointer hanging
around and not setting it back to nil. It's absolutely amusing though to read
some comments in these FreeAndNil threads and what some people interpret into
people's abilities on the base of using FreeAndNil or not. Let's have that
same discussion about assert, will we? Cause it's very similar, needs lots
more CPU cycles, is useless in perfectly designed as well error free code. I'm
sure the camps will look very similar ;)

-- 

Hannes Danzl / NexusDB

Manuals - http://www.nexusdb.com/support/index.php?q=nexusdb_manual_v3.htm
Issue Tracker - http://www.nexusdb.com/mantis/view_all_bug_page.php
Newsgroup Web Gateway - http://www.nexusdb.com/forums/
Newsgroup Search - http://www.nexusdb.com/forums/search.php
0
Hannes
10/21/2010 4:40:42 AM
Quentin Correll wrote:

> Rudy,
> 
> >  There are many grades of bad design. It is not a boolean
> >  thing.
> 
> Yep.  And as I tack-on things to old code that once seemed like "good
> design" it seems to go bad and then from bad to worse design.  ;-)

When you are young, you tend to write fast and dirty code, and when you
get more experienced, you tend to get more interested in safety and
maintainability.

-- 
Rudy Velthuis (TeamB)        http://www.teamb.com

"In this world, nothing is certain but death and taxes."
 -- Benjamin Franklin.
0
Rudy
10/22/2010 7:12:47 PM
Andrew Fionik wrote:

> On 19.10.2010 18:37, Paul Scott wrote:
> > As I've asked before: In exactly which parallel universe could that
> > considered a "bad" practice and leaving a dangling pointer to
> > deallocated memory considered "good"?
> 
> The whole thread turned into an argument.
> 
> - FreeAndNil is useful for catching errors.
> - Well... yeah... just don't make errors and you don't need
> FreeAndNil.

If that is what you got out of it, you didn't understand what I have
been saying. The errors you can catch with FreeAndNil can't happen if
you avoid certain situations.

IOW, if you don't have a car, you don't need car insurance. If you
never go into a bar, you can't get into a bar brawl. Something like
that. That is what I mean with avoiding situations.
-- 
Rudy Velthuis (TeamB)        http://www.teamb.com

Heller's Law: The first myth of management is that it exists.
0
Rudy
10/22/2010 7:18:48 PM
Hannes Danzl wrote:

> > - FreeAndNil is useful for catching errors.
> > - Well... yeah... just don't make errors and you don't need
> > FreeAndNil.
> 
> LOL! I rather stay in the camp that admits to make erros and use
> FreeAndNil. I seriously don't give a damn about the few cycles more,
> about some people thinking it's bad design or even bad code. To be
> perfectly honest for ME it's bad design to free an instance and leave
> the variable pointer hanging around and not setting it back to nil.

Let's talk again in 10 years, and you may think differently.

-- 
Rudy Velthuis (TeamB)        http://www.teamb.com

"If pigs could vote, the man with the slop bucket would be
 elected swineherd every time, no matter how much slaughtering
 he did on the side."
 -- Orson Scott Card
0
Rudy
10/22/2010 7:19:39 PM
Thorsten Engler wrote:

> In my experience, using FreeAndNil helps FIND bad code (access to
> already freed objects) instead of hiding it by causing an AV instead
> of accessing memory (usually without causing an exception) which
> (especially in multi-threaded applications) is already in use for
> something else, causing a seemingly totally unrelated crash sometime
> later.

IME, if FreeAndNil can help find bad code, the overall design of the
code shoulld be changed thus that such bad code is impossible to happen.

-- 
Rudy Velthuis (TeamB)        http://www.teamb.com

"Some men, in order to prevent the supposed intentions of their
 adversaries, have committed the most enormous cruelties."
 -- Clearchus, in Xenophon
0
Rudy
10/22/2010 7:23:45 PM
Pieter Zijlstra wrote:

> And to answer somebody else's question:
> 1) whenever I see a useless FreeAndNil on local procedure / function /
> method object variable I do start to wonder about the programming
> skills of the author.

Exactly.
 
> 2) In other situations: whenever I see a FreeAndNil it makes me wonder
> why it used.

In my case: most of the times, yes.
 
> 3) Just using Free is (or should be) the one and only recommended way
> of freeing objects (and in some cases interfaces and/or records).
> Those who are arguing that one could as well use Destroy in certain
> circumstances should really check out all available Free methods of
> all stock TObject descendants before saying so.

Good advice.

-- 
Rudy Velthuis (TeamB)        http://www.teamb.com

"One word sums up probably the responsibility of any Governor, 
 and that one word is 'to be prepared'." -- George W. Bush
0
Rudy
10/22/2010 7:24:31 PM
Rudy,

| |  Yep.  And as I tack-on things to old code that once seemed like
| | "good  design" it seems to go bad and then from bad to worse
| | design.  ;-)
| 
| When you are young, you tend to write fast and dirty code, and when
| you get more experienced, you tend to get more interested in safety
| and maintainability.

But, but, but,...  I have code I wrote when not so young that has gone
that way. <sigh ;->

Seriously, something I find that I do is "hurry" a small project
without any specific "design phase" consideration(s).  Just sit down
and code.  I often "get away with it."  However, sometimes it bites me
in the behind. <g>


-- 

   Q

10/22/2010 12:54:27

XanaNews Version 1.19.1.278  [Q'sBrokenToolBar]
0
Quentin
10/22/2010 7:59:20 PM
Quentin Correll wrote:

> Rudy,
> 
> >  |  Yep.  And as I tack-on things to old code that once seemed like
> >  | "good  design" it seems to go bad and then from bad to worse
> >  | design.  ;-)
> >  
> >  When you are young, you tend to write fast and dirty code, and when
> >  you get more experienced, you tend to get more interested in safety
> >  and maintainability.
> 
> But, but, but,...  I have code I wrote when not so young that has gone
> that way. <sigh ;->
> 
> Seriously, something I find that I do is "hurry" a small project
> without any specific "design phase" consideration(s).  Just sit down
> and code.  I often "get away with it."  However, sometimes it bites me
> in the behind. <g>

You probably get into trouble if the "hurry" project takes on a long
life after all. <g>

-- 
Rudy Velthuis (TeamB)        http://www.teamb.com

"Liberty and democracy become unholy when their hands are dyed
 red with innocent blood." -- Mahatma Gandhi
0
Rudy
10/22/2010 8:04:07 PM
Rudy,

| Heller's Law: The first myth of management is that it exists.

Anyone seen our old acquaintance Steve around recently?  

After he married Susan he seemed to "disconnect" from "the ol'days."  I
lost contact with him a few years ago.

-- 

   Q

10/22/2010 13:00:30

XanaNews Version 1.19.1.278  [Q'sBrokenToolBar]
0
Quentin
10/22/2010 8:04:58 PM
Rudy,

| You probably get into trouble if the "hurry" project takes on a long
| life after all. <g>

Yep.  <g>

-- 

   Q

10/22/2010 14:46:18

XanaNews Version 1.19.1.278  [Q'sBrokenToolBar]
0
Quentin
10/22/2010 9:46:52 PM
On 23.10.2010 1:18, Rudy Velthuis (TeamB) wrote:
> If that is what you got out of it, you didn't understand what I have
> been saying. The errors you can catch with FreeAndNil can't happen if
> you avoid certain situations.

The situations I'm talking about is not that kind of situations which 
you can avoid not matter how sane and cautionous you are.

> IOW, if you don't have a car, you don't need car insurance. If you
> never go into a bar, you can't get into a bar brawl. Something like
> that. That is what I mean with avoiding situations.

Brawls happen in cafees and restaurants also. They happen also on 
streets. From that perspective I'd rather be prepared for a brawl and 
not to go to bars anyway, than simply not to go to bars. I hope you 
understand the difference.
0
Andrew
10/23/2010 9:21:08 AM
Andrew Fionik wrote:

> On 23.10.2010 1:18, Rudy Velthuis (TeamB) wrote:
> > If that is what you got out of it, you didn't understand what I have
> > been saying. The errors you can catch with FreeAndNil can't happen
> > if you avoid certain situations.
> 
> The situations I'm talking about is not that kind of situations which 
> you can avoid not matter how sane and cautionous you are.

Example? I am not talking about avoiding doing certain things, I am
talking about how you go about doing them. Avoiding situations where
FreeAndNil might have an effect (if only for debugging) is pretty easy,
IME.
 
> > IOW, if you don't have a car, you don't need car insurance. If you
> > never go into a bar, you can't get into a bar brawl. Something like
> > that. That is what I mean with avoiding situations.
> 
> Brawls happen in cafees and restaurants also. They happen also on 
> streets. 

Not bar brawls. And it is never a good idea to stretch an analogy. How
do they say? If you can't stand the heat... Well, I avoid the kitchen,
although I am not afraid of the heat. <g>

> From that perspective I'd rather be prepared for a brawl and 
> not to go to bars anyway, than simply not to go to bars. I hope you 
> understand the difference.

Yes, I do. Think about the car insurance thing.

-- 
Rudy Velthuis (TeamB)        http://www.teamb.com

"Intellectuals solve problems; geniuses prevent them."
 -- Albert Einstein
0
Rudy
10/24/2010 11:43:55 AM
On 24.10.2010 17:43, Rudy Velthuis (TeamB) wrote:
> Example? I am not talking about avoiding doing certain things, I am
> talking about how you go about doing them. Avoiding situations where
> FreeAndNil might have an effect (if only for debugging) is pretty easy,
> IME.

I posted it here already. It happens not because you do something 
incorrect in principle. It happens because you forget to do something, 
or you are unaware of something, or you misunderstand something, or 
there are ways of using of your code which you don't forsee, or your 
expectations are wrong, etc.

>>> IOW, if you don't have a car, you don't need car insurance. If you
>>> never go into a bar, you can't get into a bar brawl. Something like
>>> that. That is what I mean with avoiding situations.
>>
>> Brawls happen in cafees and restaurants also. They happen also on
>> streets.

> Not bar brawls. And it is never a good idea to stretch an analogy.

They are brawls anyway, the only thing changes is the name of a brawl. 
It is never a good idea to bring vague and misty arguments and analogies 
into a technical discussion. Exactly because they are so easy to stretch.

 > How do they say? If you can't stand the heat... Well, I avoid the 
kitchen, although I am not afraid of the heat.

I'm not sure if I understand this proverb well. However, we have an 
exactly opposite proverb (can't translate it from Russian) which could 
be understood as "If you are in the kitchen do your work well and don't 
say that you can't stand the heat". Another one is "The fear of 
encountering a wolf is not an excuse for not going into a forest". :)

>>  From that perspective I'd rather be prepared for a brawl and
>> not to go to bars anyway, than simply not to go to bars. I hope you
>> understand the difference.

> Yes, I do. Think about the car insurance thing.

Ride a BTR.
0
Andrew
10/24/2010 1:12:27 PM
Andrew Fionik wrote:

> On 24.10.2010 17:43, Rudy Velthuis (TeamB) wrote:
> > Example? I am not talking about avoiding doing certain things, I am
> > talking about how you go about doing them. Avoiding situations where
> > FreeAndNil might have an effect (if only for debugging) is pretty
> > easy, IME.
> 
> I posted it here already.

If you mean what you posted already (the one with the tree and the
treeview) I'm sure that if you put some thought to it, it could be done
completely differently, avoiding the risks.

Or did you mean the case where you (or someone else? - this thread is
too long to go over it again, sorry) used an object two lines after
freeing it. That is invalid, IMO.
-- 
Rudy Velthuis (TeamB)        http://www.teamb.com

"Think my friends! You adulate a stone as Vishnu but you cannot
 see God in a fellow man."
 -- Sankaracharya
0
Rudy
10/24/2010 5:49:31 PM
Thorsten Engler wrote:

> Pieter Zijlstra wrote:
> 
> > it was about (ab)using
> > it to fix certain problems, or more over, some recommending it to
> > use it in less obvious code locations (like destructors) and
> > therefor hiding a bad code design (and I'm not talking about the
> > more obvious coding errors some are discussing here in more recent
> > threads).
> 
> In my experience, using FreeAndNil helps FIND bad code (access to
> already freed objects) instead of hiding it by causing an AV instead
> of accessing memory (usually without causing an exception) which
> (especially in multi-threaded applications) is already in use for
> something else, causing a seemingly totally unrelated crash sometime
> later.

I'm not denying that accessing an object after using FreeAndNil will
cause an AV. I do disagree about the multi-threaded part in your post
unless the other thread is accessing the same object (pointer).

I have never been in the situation while debugging a problem to come to
the conclusion that if I would have used FreeAndNil I would have found
the problem earlier in the process.

I do see a lot of situations which makes me think WTF was the author
thinking when he/she wrote this, like ...

{code}
procedure TListOfSomeObjects.Delete(object: TSomeObject);
var
 I: Integer;
begin
  I := FListOfSomeObjects.IndexOfObject(object);
  if I >= 0 then
  begin
    FListOfSomeObjects.Delete(idx);
    FreeAndNil(object);
    SaveToRegistry;
  end;
end;
{code}

.... and I can give you a lot more examples where FreeAndNil only adds
confusion about the intentions of the original author and most of the
times it didn't serve any purpose.
 
> > 3) Just using Free is (or should be) the one and only recommended
> > way of freeing objects (and in some cases interfaces and/or
> > records). Those who are arguing that one could as well use Destroy
> > in certain circumstances should really check out all available Free
> > methods of all stock TObject descendants before saying so.
> 
> Free is not virtual. Free should never be overridden as there is no
> guarantee that it will ever be called. e.g. if you use FreeAndNil any
> overridden Free wouldn't be called. As such I don't think you ever
> need to worry about someone overriding Free.

But still Free is "overridden" sometimes even in the RTL/VCL.
Use the following "procedure T.*\.Free;" reg-expression / search string
on the Delphi source directories.  I'm not saying this is a good thing
(nor am I'm saying this is a bad thing) I'm just saying that it happens
and that blindly using FreeAndNil everywhere can/will cause problems.

-- 
Pieter

"I know of no crime that has not been defended by the church,
 in one form or other. The church is not a pioneer; it accepts a
 new truth, last of all, and only when denial has become
 useless."
 -- Robert G. Ingersoll
0
Pieter
10/24/2010 11:23:16 PM
Pieter,

| I do see a lot of situations which makes me think WTF was the author
| thinking when he/she wrote this, like ...

I encounter that in my own code every once in a while.  <g>

-- 

   Q

10/24/2010 17:20:52

XanaNews Version 1.19.1.278  [Q'sBrokenToolBar]
0
Quentin
10/25/2010 12:21:24 AM
Pieter Zijlstra wrote:

> I'm not denying that accessing an object after using FreeAndNil will
> cause an AV. I do disagree about the multi-threaded part in your post
> unless the other thread is accessing the same object (pointer).

The sequence of events is very simple:

ThreadA: free object (-> FreeMem)
ThreadB: GetMem which ends up getting a pointer to the memory "freed" by ThreadA
ThreadB: write some values into that memory
ThreadA: set a field on the freed object, overwriting memory owned by ThreadB

.... any time later:

AnyThread: access memory that was allocated by ThreadB and then corrupted: crash

> I have never been in the situation while debugging a problem to come to
> the conclusion that if I would have used FreeAndNil I would have found
> the problem earlier in the process.

I've had a few of these over the years where I got a crash report (with
callstack) that didn't make any sense and was (almost) impossible to reproduce.

Tracking these down takes forever because the source of the problem is totally
unrelated to the point where you see the crash.

And any use of breakpoints or logging code will end up changing the timings and
can make the crash that you see go away or move to a totally different place
(if it was reproducibly in the same place to begin with, which it usually
isn't).

In all cases, the use of FreeAndNil in the right place then resulted in an AV
in the context of the thread where the actual problem (the access after being
freed) is which then allowed to proper debug that.
0
Thorsten
10/25/2010 1:51:52 AM
On 24.10.2010 23:49, Rudy Velthuis (TeamB) wrote:
> If you mean what you posted already (the one with the tree and the
> treeview) I'm sure that if you put some thought to it, it could be done
> completely differently, avoiding the risks.

I was asking an example from you to see how you avoid the risks.

> Or did you mean the case where you (or someone else? - this thread is
> too long to go over it again, sorry) used an object two lines after
> freeing it. That is invalid, IMO.

It precisely demonstrates my POV.

You use FreeAndNil. You do something wrong (not on design level). It 
crashes where the problem is.

You don't use FreeAndNil. It doesn't crash and displays the wrong results.
0
Andrew
10/25/2010 2:29:23 AM
"Thorsten Engler"  wrote
>
> The sequence of events is very simple:
>
> ThreadA: free object (-> FreeMem)
> ThreadB: GetMem which ends up getting a pointer to the memory "freed" by 
> ThreadA
> ThreadB: write some values into that memory
> ThreadA: set a field on the freed object, overwriting memory owned by 
> ThreadB
>
> ... any time later:
>
> AnyThread: access memory that was allocated by ThreadB and then corrupted: 
> crash
>
>
> I've had a few of these over the years where I got a crash report (with
> callstack) that didn't make any sense and was (almost) impossible to 
> reproduce.
>
> Tracking these down takes forever because the source of the problem is 
> totally
> unrelated to the point where you see the crash.
>
> And any use of breakpoints or logging code will end up changing the 
> timings and
> can make the crash that you see go away or move to a totally different 
> place
> (if it was reproducibly in the same place to begin with, which it usually
> isn't).
>
> In all cases, the use of FreeAndNil in the right place then resulted in an 
> AV
> in the context of the thread where the actual problem (the access after 
> being
> freed) is which then allowed to proper debug that.

This (as it appears to me) has grown beyond any real question of whether 
FreeAndNil use is good or bad.

The example above is clearly a question of writing thread-safe code and 
nothing else.

And to the best of my knowledge FreeAndNil is NOT - repeat NOT threadsafe.
end of story.
0
Sven
10/25/2010 10:06:31 AM
> This (as it appears to me) has grown beyond any real question of whether 
> FreeAndNil use is good or bad.
> 
> The example above is clearly a question of writing thread-safe code and 
> nothing else.
> 
> And to the best of my knowledge FreeAndNil is NOT - repeat NOT threadsafe.
> end of story.

You clearly either haven't bothered to read what I wrote or you didn't
understand it.

ThreadA does something (buggy) along the lines of:

var
  x: TSomeObject;
begin
  x := TSomeObject.Create;
  {...}
  x.Free;
  {...}
  x.SomeField := 123;
end;

No multi-threaded access to anything involved here. Just a bug involving access
to an already freed object. The assignment to x.SomeField succeeds without a
crash because x still points to the place on the heap where the TSomeObject
used to be. But by that time that memory has already been returned to the
memory manger.

ThreadB does something (not buggy) like this:

var
  y := TSomeOtherObject;
begin
  y := TSomeOtherObject.Create;
  y.StringField := 'abc';
end;

These 2 threads have absolutely nothing to do with each other. There is no
concurrent access to any shared variable.

Now suppose these 2 threads execute concurrently and mixed together, the
following instructions get executed:

  x := TSomeObject.Create;

  x.Free; 
  // calls FreeMem, returning the memory to the memory manager

  y := TSomeOtherObject.Create; 
  // calls GetMem, getting the memory that the call to FreeMem just gave
  // back to the memory manager
  // x=y now
  
  x.SomeField := 123;
  // writes into memory that is no longer owned by x

  y.StringField := 'abc';
  // lets assume SomeField and StringField are at the same offset
  // this assignment will crash because the compiler is treating the
  // value 123 as a pointer into the heap, trying to reduce the reference 
  // count of that 'string'

So what you have here is 2 pieces of code. Both completely independent. Without
any threading issues and which should never ever attempt to access the same
memory concurrently.

But because they are running in the same address space and the memory manager
will use the same memory that was just returned by one thread to fulfil an
allocation request from another thread, you now have concurrent access to the
same memory.

If you get a callstack of the crash in ThreadB, there is absolutely no
indication that the crash was caused by something that the totally unrelated
ThreadA did.

Now lets do the same with FreeAndNil:

  x := TSomeObject.Create;
  FreeAndNil(x);
  y := TSomeOtherObject.Create; 
  x.SomeField := 123;
  // will crash in the context of ThreadA because x is nil

There, you directly see what the problem is and can debug it.
0
Thorsten
10/25/2010 11:59:14 AM
"Thorsten Engler"  wrote in message news:[email protected]
>> This (as it appears to me) has grown beyond any real question of whether
>> FreeAndNil use is good or bad.
>>
>> The example above is clearly a question of writing thread-safe code and
>> nothing else.
>>
>> And to the best of my knowledge FreeAndNil is NOT - repeat NOT 
>> threadsafe.
>> end of story.
>
> You clearly either haven't bothered to read what I wrote or you didn't
> understand it.
>
> ThreadA does something (buggy) along the lines of:
>
> var
>  x: TSomeObject;
> begin
>  x := TSomeObject.Create;
>  {...}
>  x.Free;
>  {...}
>  x.SomeField := 123;
> end;
>
> No multi-threaded access to anything involved here. Just a bug involving 
> access
> to an already freed object. The assignment to x.SomeField succeeds without 
> a
> crash because x still points to the place on the heap where the 
> TSomeObject
> used to be. But by that time that memory has already been returned to the
> memory manger.
>
> ThreadB does something (not buggy) like this:
>
> var
>  y := TSomeOtherObject;
> begin
>  y := TSomeOtherObject.Create;
>  y.StringField := 'abc';
> end;
>
> These 2 threads have absolutely nothing to do with each other. There is no
> concurrent access to any shared variable.
>
> Now suppose these 2 threads execute concurrently and mixed together, the
> following instructions get executed:
>
>  x := TSomeObject.Create;
>
>  x.Free;
>  // calls FreeMem, returning the memory to the memory manager
>
>  y := TSomeOtherObject.Create;
>  // calls GetMem, getting the memory that the call to FreeMem just gave
>  // back to the memory manager
>  // x=y now
>
>  x.SomeField := 123;
>  // writes into memory that is no longer owned by x
>
>  y.StringField := 'abc';
>  // lets assume SomeField and StringField are at the same offset
>  // this assignment will crash because the compiler is treating the
>  // value 123 as a pointer into the heap, trying to reduce the reference
>  // count of that 'string'
>
> So what you have here is 2 pieces of code. Both completely independent. 
> Without
> any threading issues and which should never ever attempt to access the 
> same
> memory concurrently.
>
> But because they are running in the same address space and the memory 
> manager
> will use the same memory that was just returned by one thread to fulfil an
> allocation request from another thread, you now have concurrent access to 
> the
> same memory.

Your assumption is faulty.
So long as they run in the same address space they are not independent. It 
doesn't matter if they run in the same thread or in different threads,  but 
the danger is higher when they run in different threads because then they 
are running asyncronously as well.

You would have precisely the same error if in a single thread you free the 
object addressed by x and then attempt to do some work on this object after 
creating a different object addressed by y (or even worse if you reuse the 
pointer x to address your new object).

Your basic problem is apparently to keep track of when your object is 
active. One way of doing this is to have a semaphore for this purpose. In 
fact the few times I have had such problems I have usually implemented the 
object with its reference pointer both as a pointer and as the semaphore to 
indicate when it is active. In such cases my code includes a test for "nil" 
before actually operating on the object, and FreeAndNil of course serves the 
purpose of resetting the semaphore together with freeing the object.

>
> If you get a callstack of the crash in ThreadB, there is absolutely no
> indication that the crash was caused by something that the totally 
> unrelated
> ThreadA did.
>
> Now lets do the same with FreeAndNil:
>
>  x := TSomeObject.Create;
>  FreeAndNil(x);
>  y := TSomeOtherObject.Create;
>  x.SomeField := 123;
>  // will crash in the context of ThreadA because x is nil
>
> There, you directly see what the problem is and can debug it.

And if you maintain proper track of your objects then you will never have 
this problem FreeAndNil or not FreeAndNil.
0
Sven
10/25/2010 3:07:29 PM
Pieter,

On Thu, 21 Oct 2010 00:40:11 +0100, Pieter Zijlstra  
<[email protected]> wrote:

> ... Those
> who are arguing that one could as well use Destroy in certain
> circumstances should really check out all available Free methods of all
> stock TObject descendants before saying so.

Please say it ain't so, Joe!

Surely the quid-pro-quo for the decision to implement .Free as a "method"  
(IMO misguided because it breaks the whole underlying O-O paradigm) was  
that the Compiler+RTL would always know (indeed, must always know) that  
Free is in a fixed, static location and should do nothing other than "if  
Assigned then Destroy"?

-- 
Paul Scott
Information Management Systems
Macclesfield, UK
0
Paul
10/25/2010 3:09:26 PM
On Mon, 18 Oct 2010 12:36:11 +0100, Rudy Velthuis  
<[email protected]> wrote:

> Andrew Fionik wrote:
>
>> So could write it in the following way:
>>
>> if InnerObject<>nil then InnerObject.Destroy;
>
> Yes, you could. But for that, there is Free, which already does that,
> for all classes. Using Free (always, consistently, without exception)
> is less error prone than always to code the condition and call the
> destructor.

Absolutely spot on - if you just replace "Free" with "FreeAndNil"  ;)

Not nilling a pointer after discarding memory just because you /think/  
that it will never be required is surely an egregious example of the  
"premature optimisation" which you are normally so quick to discourage.

-- 
Paul Scott
Information Management Systems
Macclesfield, UK
0
Paul
10/26/2010 12:49:54 PM
Paul Scott wrote:

> On Mon, 18 Oct 2010 12:36:11 +0100, Rudy Velthuis  
> <[email protected]> wrote:
> 
> > Andrew Fionik wrote:
> > 
> >> So could write it in the following way:
> > > 
> >> if InnerObject<>nil then InnerObject.Destroy;
> > 
> > Yes, you could. But for that, there is Free, which already does
> > that, for all classes. Using Free (always, consistently, without
> > exception) is less error prone than always to code the condition
> > and call the destructor.
> 
> Absolutely spot on - if you just replace "Free" with "FreeAndNil"  ;)

Do what you like. IME, it is either obsolete or it doesn't do anything.
<g><
> 
> Not nilling a pointer after discarding memory just because you think  
> that it will never be required

No no no, I KNOW it will never be accessed anymore. Only then I can
free an object. If I don't know, it can't be freed yet. But not knowing
is IMO a big design error. That is what I am saying all the time. That
is what your code must ensure (and that is not so hard either).
-- 
Rudy Velthuis (TeamB)        http://www.teamb.com

Brilliant's Law Of Limited Ambition: If you can't learn how to do 
it well learn how to enjoy doing it poorly.
0
Rudy
10/26/2010 5:12:24 PM
Andrew Fionik wrote:

> On 24.10.2010 23:49, Rudy Velthuis (TeamB) wrote:
> > If you mean what you posted already (the one with the tree and the
> > treeview) I'm sure that if you put some thought to it, it could be
> > done completely differently, avoiding the risks.
> 
> I was asking an example from you to see how you avoid the risks.

That depends on the overall design. What you posted did indeed have its
problems, and that is why it should not be done like that.
> 
> > Or did you mean the case where you (or someone else? - this thread
> > is too long to go over it again, sorry) used an object two lines
> > after freeing it. That is invalid, IMO.
> 
> It precisely demonstrates my POV.

My POV is that that is paranoid programming. If you can't even control
what you do INSIDE a short routine, then you have other problems IMO.
You said you were tired. Well, there you are.
 
> You use FreeAndNil. You do something wrong (not on design level). It 
> crashes where the problem is.

If you can't even avoid doing such things wrong (using an object you
freed a few lines ago in the same routine), then you should program a
little more carefully.

-- 
Rudy Velthuis (TeamB)        http://www.teamb.com

"If cats looked like frogs we'd realize what nasty, cruel little 
 bastards they are. Style. That's what people remember."
 -- Terry Pratchett (Lords and Ladies)
0
Rudy
10/26/2010 5:18:15 PM
Pieter Zijlstra wrote:

> I'm not denying that accessing an object after using FreeAndNil will
> cause an AV. I do disagree about the multi-threaded part in your post
> unless the other thread is accessing the same object (pointer).
> 
> I have never been in the situation while debugging a problem to come
> to the conclusion that if I would have used FreeAndNil I would have
> found the problem earlier in the process.

Indeed.

-- 
Rudy Velthuis (TeamB)        http://www.teamb.com

"So I went to the dentist. He said "Say Aaah." I said "Why?"
 He said "My dog's died.'" -- Tommy Cooper
0
Rudy
10/26/2010 5:20:08 PM
Thorsten Engler wrote:

> ... any time later:
> 
> AnyThread: access memory that was allocated by ThreadB and then
> corrupted: crash

That "any time later" part is exactly what should not be possible, if
the design was done differently. And I wonder how FreeAndNil would
prevent it.

-- 
Rudy Velthuis (TeamB)        http://www.teamb.com

"The establishment of Christianity arrested the normal
 development of the physical sciences for over fifteen hundred
 years."
 -- Andrew Dickson White
0
Rudy
10/26/2010 5:22:54 PM
Thorsten Engler wrote:

> ThreadA does something (buggy) along the lines of:
> 
> var
>   x: TSomeObject;
> begin
>   x := TSomeObject.Create;
>   {...}
>   x.Free;
>   {...}
>   x.SomeField := 123;
> end;

If you can't avoid such errors, the use of FreeAndNil, or not, is the
least of your problems, IMO. I expect any programmer to be able to spot
such errors immediately (or actually, never to make them: one should -
at any one time - know which objects in the same routine are usable and
which aren't; otherwise you might just as well use uninitialised object
references):

  var
    x: TSomeObject;
  begin
    ...
    x.SomeField := 123;
  end;

IMO the code you posted is just as bad as the above. It should simply
never happen.

-- 
Rudy Velthuis (TeamB)        http://www.teamb.com

"I don't know that atheists should be considered citizens, nor
 should they be considered patriots. This is one nation under
 God."
 -- President George Bush, August 27, 1988
0
Rudy
10/26/2010 5:30:06 PM
On 26.10.2010 23:12, Rudy Velthuis (TeamB) wrote:
> No no no, I KNOW it will never be accessed anymore. Only then I can
> free an object. If I don't know, it can't be freed yet. But not knowing
> is IMO a big design error. That is what I am saying all the time. That
> is what your code must ensure (and that is not so hard either).

That's the difference in our approach. You KNOW, but others KNOW than 
you only THINK THAT YOU KNOW. :)
0
Andrew
10/27/2010 4:04:44 AM
On 26.10.2010 23:18, Rudy Velthuis (TeamB) wrote:
> That depends on the overall design. What you posted did indeed have its
> problems, and that is why it should not be done like that.

Of course it shouldn't. But it happens sometimes.

> My POV is that that is paranoid programming. If you can't even control
> what you do INSIDE a short routine, then you have other problems IMO.
> You said you were tired. Well, there you are.

Does it change anything? People get tired. Errors happen.

> If you can't even avoid doing such things wrong (using an object you
> freed a few lines ago in the same routine), then you should program a
> little more carefully.

I know some people who claim that they are able to do such things right, 
but some time they ask: "Can you look at my code? It should work but it 
doesn't work as expected. I can't understand what is wrong" and after a 
glance I see a trivial error.

Rudy, I have an impression that I'm talking to a robot not to a human. A 
perfect machine which absolutely sure that it doesn't make errors.
0
Andrew
10/27/2010 4:28:48 AM
Andrew Fionik wrote:

> On 26.10.2010 23:12, Rudy Velthuis (TeamB) wrote:
> > No no no, I KNOW it will never be accessed anymore. Only then I can
> > free an object. If I don't know, it can't be freed yet. But not
> > knowing is IMO a big design error. That is what I am saying all the
> > time. That is what your code must ensure (and that is not so hard
> > either).
> 
> That's the difference in our approach. You KNOW, but others KNOW than 
> you only THINK THAT YOU KNOW. :)

No. <g>

It is not too hard to actually KNOW what you are doing. It is actually
quite a problem if you don't. Then you may need FreeAndNil, indeed.

-- 
Rudy Velthuis (TeamB)        http://www.teamb.com

"The death of dogma is the birth of morality."
 -- Immanuel Kant
0
Rudy
10/27/2010 10:47:48 AM
Andrew Fionik wrote:

> On 26.10.2010 23:18, Rudy Velthuis (TeamB) wrote:
> > That depends on the overall design. What you posted did indeed have
> > its problems, and that is why it should not be done like that.
> 
> Of course it shouldn't. But it happens sometimes.

Not if you have proper design.

> > My POV is that that is paranoid programming. If you can't even
> > control what you do INSIDE a short routine, then you have other
> > problems IMO.  You said you were tired. Well, there you are.
> 
> Does it change anything? People get tired. Errors happen.

Indeed. But such errors are inexcusable, IMO. If you make them, your
problem is not solved by using FreeAndNil.
 
> > If you can't even avoid doing such things wrong (using an object you
> > freed a few lines ago in the same routine), then you should program
> > a little more carefully.
> 
> I know some people who claim that they are able to do such things
> right, but some time they ask: "Can you look at my code?

Every programmer should be unable to do them wrong. If you don't even
know what you did two lines before, there is a problem that is not
solved by "paranoid programming".

-- 
Rudy Velthuis (TeamB)        http://www.teamb.com

"A model is done when nothing else can be taken out." -- Dyson
0
Rudy
10/27/2010 10:51:19 AM
On Wed, 27 Oct 2010 11:47:48 +0100, Rudy Velthuis  
<[email protected]> wrote:

>> That's the difference in our approach. You KNOW, but others KNOW than
>> you only THINK THAT YOU KNOW. :)
>
> No. <g>
>
> It is not too hard to actually KNOW what you are doing.It is actually  
> quite a problem if you don't.Then you may need FreeAndNil, indeed.

No. <g>

It is not too hard to actually KNOW what you THINK you are doing.

It is actually quite HUMAN if you don't... implement (even a perfect  
design) absolutely perfectly.

Then you may find FreeAndNil causes subsequent AVs which make it obvious  
if your design and implementation are not as perfect as you had hoped.

Then it may also help you to track down those design/implementation  
imperfections faster.


Of course, both nilling pointers and the use of ASSERTs are a complete  
waste of CPU cycles if your design and implementation - and each and every  
future modification - are all perfect.


-- 
Paul Scott
Information Management Systems
Macclesfield, UK
0
Paul
10/27/2010 1:15:18 PM
Paul Scott wrote:

> On Wed, 27 Oct 2010 11:47:48 +0100, Rudy Velthuis  
> <[email protected]> wrote:
> 
> >> That's the difference in our approach. You KNOW, but others KNOW
> than >> you only THINK THAT YOU KNOW. :)
> > 
> > No. <g>
> > 
> > It is not too hard to actually KNOW what you are doing.It is
> > actually quite a problem if you don't.Then you may need FreeAndNil,
> > indeed.
> 
> No. <g>
> 
> It is not too hard to actually KNOW what you THINK you are doing.

This is getting silly. 
-- 
Rudy Velthuis (TeamB)        http://www.teamb.com

"Peace is over rated. Any slave can have peace. Just pick the
 cotton."
 -- TheSong
0
Rudy
10/27/2010 1:30:39 PM
On Wed, 27 Oct 2010 14:30:39 +0100, Rudy Velthuis  
<[email protected]> wrote:

> Paul Scott wrote:
>
>> On Wed, 27 Oct 2010 11:47:48 +0100, Rudy Velthuis
>> <[email protected]> wrote:
>>
>> >> That's the difference in our approach. You KNOW, but others KNOW
>> than >> you only THINK THAT YOU KNOW. :)
>> >
>> > No. <g>
>> >
>> > It is not too hard to actually KNOW what you are doing.It is
>> > actually quite a problem if you don't.Then you may need FreeAndNil,
>> > indeed.
>>
>> No. <g>
>>
>> It is not too hard to actually KNOW what you THINK you are doing.
>
> This is getting silly.

Not at all - you keep forgetting that large projects can contain many  
hundreds of units and many thousands of methods written and modified over  
many years by many different programmers - of many varying degrees of  
quality.

When you are told to "just add this feature", you may THINK you KNOW what  
the original designer intended, but you can never KNOW for certain that  
the design was indeed perfect; and was correctly implemented; and does  
catch all corner-cases. Nor can you KNOW that any previous "quick-fixes"  
haven't compromised the design. All you KNOW is that previous testing has  
eliminated (or maybe just hidden) the most obvious faults.

Further, the Delphi RAD IDE positively encourages newcomers to put their  
code into event handlers. Programmers may THINK that that they know which  
events are fired and in which order, but as the questions in these forums  
often illustrate, even people with many years' experience don't always  
KNOW precisely when (and in which order) their code will be executed.

-- 
Paul Scott
Information Management Systems
Macclesfield, UK
0
Paul
10/27/2010 2:46:16 PM
Paul Scott wrote:

> On Wed, 27 Oct 2010 14:30:39 +0100, Rudy Velthuis  
> <[email protected]> wrote:
> 
> > Paul Scott wrote:
> > 
> >> On Wed, 27 Oct 2010 11:47:48 +0100, Rudy Velthuis
> >> <[email protected]> wrote:
> > > 
> >> >> That's the difference in our approach. You KNOW, but others KNOW
> >> than >> you only THINK THAT YOU KNOW. :)
> >> >
> >> > No. <g>
> >> >
> >> > It is not too hard to actually KNOW what you are doing.It is
> >> > actually quite a problem if you don't.Then you may need
> FreeAndNil, >> > indeed.
> > > 
> >> No. <g>
> > > 
> >> It is not too hard to actually KNOW what you THINK you are doing.
> > 
> > This is getting silly.
> 
> Not at all

Yes, it is, IMO. Trying to mimic each other's style of writing is
silly, IMO. May be fun once or twice, but not if done in perpetuity.

Let's agree that we completely disagree. 

I tend to design thus that what you and others describe CAN'T happen
(except if you really have no oversight over the code you are
currently working on and use objects freed a few lines ago in the same
routine). You say they can still happen. This is not my experience. I
have never needed FreeAndNil (I used it once, in a very old component,
and after that, not anymore) and using it would not do my code any good
(and I don't mean it is beyond any salvation either <g>).

I know that I am not very good at explaining how I completely avoid
code that frees objects when they may still be needed. This is because
it is not something I really do consciously, just intuitively. I will
try to lay out a few rules, but not right now. I'll have to think about
it more.

-- 
Rudy Velthuis (TeamB)        http://www.teamb.com

"Logic is in the eye of the logician."
 -- Gloria Steinem

Edited by: Rudy Velthuis (TeamB) on Oct 27, 2010 5:31 PM - changed "about" in "over"
0
Rudy
10/27/2010 3:32:06 PM
Am 27.10.2010 17:29, schrieb Rudy Velthuis (TeamB):

> I know that I am not very good at explaining how I completely avoid
> code that frees objects when they may still be needed.

That's an easy one: don't call Free at all.

Christian
0
Christian
10/27/2010 3:32:59 PM
Christian Gudrian wrote:

> Am 27.10.2010 17:29, schrieb Rudy Velthuis (TeamB):
> 
> > I know that I am not very good at explaining how I completely avoid
> > code that frees objects when they may still be needed.
> 
> That's an easy one: don't call Free at all.

That's silly too. 

I do free objects, but not too early, and I do know that if I do that,
there are NO references - there can't be any references (but the last
one, of course) to them anymore.
-- 
Rudy Velthuis (TeamB)        http://www.teamb.com

"There is always a certain meanness in the argument of
 conservatism, joined with a certain superiority in its fact."
 -- Ralph Waldo Emerson
0
Rudy
10/27/2010 3:35:39 PM
Reply:
(Thread closed)