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 |
![]() |
> {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 |
![]() |
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 |
![]() |
> {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 |
![]() |
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 |
![]() |
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 |
![]() |
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 |
![]() |
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 |
![]() |
> {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 |
![]() |
> {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 |
![]() |
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 |
![]() |
> {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 |
![]() |
> 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 |
![]() |
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 |
![]() |
> {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 |
![]() |
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 |
![]() |
> {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 |
![]() |
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 |
![]() |
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 |
![]() |
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 |
![]() |
> 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 |
![]() |
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 |
![]() |
> 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 |
![]() |
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 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 |
![]() |
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 |
![]() |
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 |
![]() |
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 |
![]() |
> {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 |
![]() |
> {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 |
![]() |
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 |
![]() |
> {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 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 |
![]() |
> {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 |
![]() |
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 |
![]() |
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 |
![]() |
"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 |
![]() |
> {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 |
![]() |
> {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 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 |
![]() |
> {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 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 |
![]() |
> {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 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 |
![]() |
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 |
![]() |
> {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 |
![]() |
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 |
![]() |
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 |
![]() |
> {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 |
![]() |
> {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 |
![]() |
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 |
![]() |
> {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 |
![]() |
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 |
![]() |
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 |
![]() |
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 |
![]() |
> {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 |
![]() |
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 |
![]() |
> {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 |
![]() |
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 |
![]() |
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 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 |
![]() |
"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 |
![]() |
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 |
![]() |
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 |
![]() |
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 |
![]() |
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 |
![]() |
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 |
![]() |
> {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 |
![]() |
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 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 |
![]() |
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 |
![]() |
> 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 |
![]() |
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 |
![]() |
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 |
![]() |
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 |
![]() |
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 |
![]() |
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 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 |
![]() |
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 |
![]() |
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 |
![]() |
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 |
![]() |
> {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 |
![]() |
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 |
![]() |
> 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 |
![]() |
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 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, | 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 |
![]() |
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 |
![]() |
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 |
![]() |
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 |
![]() |
> - 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 |
![]() |
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 |
![]() |
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 |
![]() |
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 |
![]() |
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 |
![]() |
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, | | 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 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, | 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 |
![]() |
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 |
![]() |
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 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 |
![]() |
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 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 |
![]() |
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, | 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 |
![]() |
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 |
![]() |
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 |
![]() |
"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 |
![]() |
> 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 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 |
![]() |
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 |
![]() |
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 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 |
![]() |
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 |
![]() |
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 |
![]() |
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 |
![]() |
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 |
![]() |
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 |
![]() |
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 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 |
![]() |
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 |
![]() |
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 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 |
![]() |
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 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 |
![]() |
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 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 |
![]() |