<html xmlns:v="urn:schemas-microsoft-com:vml" xmlns:o="urn:schemas-microsoft-com:office:office" xmlns:w="urn:schemas-microsoft-com:office:word" xmlns:m="http://schemas.microsoft.com/office/2004/12/omml" xmlns="http://www.w3.org/TR/REC-html40"><head><meta http-equiv=Content-Type content="text/html; charset=us-ascii"><meta name=Generator content="Microsoft Word 12 (filtered medium)"><style><!--
/* Font Definitions */
@font-face
        {font-family:Wingdings;
        panose-1:5 0 0 0 0 0 0 0 0 0;}
@font-face
        {font-family:"Cambria Math";
        panose-1:2 4 5 3 5 4 6 3 2 4;}
@font-face
        {font-family:Calibri;
        panose-1:2 15 5 2 2 2 4 3 2 4;}
@font-face
        {font-family:Tahoma;
        panose-1:2 11 6 4 3 5 4 4 2 4;}
@font-face
        {font-family:Consolas;
        panose-1:2 11 6 9 2 2 4 3 2 4;}
/* Style Definitions */
p.MsoNormal, li.MsoNormal, div.MsoNormal
        {margin:0cm;
        margin-bottom:.0001pt;
        font-size:12.0pt;
        font-family:"Times New Roman","serif";
        color:black;}
a:link, span.MsoHyperlink
        {mso-style-priority:99;
        color:blue;
        text-decoration:underline;}
a:visited, span.MsoHyperlinkFollowed
        {mso-style-priority:99;
        color:purple;
        text-decoration:underline;}
pre
        {mso-style-priority:99;
        mso-style-link:"HTML Preformatted Char";
        margin:0cm;
        margin-bottom:.0001pt;
        font-size:10.0pt;
        font-family:"Courier New";
        color:black;}
span.HTMLPreformattedChar
        {mso-style-name:"HTML Preformatted Char";
        mso-style-priority:99;
        mso-style-link:"HTML Preformatted";
        font-family:Consolas;
        color:black;}
span.EmailStyle19
        {mso-style-type:personal;
        font-family:"Calibri","sans-serif";
        color:#1F497D;}
span.EmailStyle20
        {mso-style-type:personal;
        font-family:"Calibri","sans-serif";
        color:#1F497D;}
span.EmailStyle21
        {mso-style-type:personal-reply;
        font-family:"Calibri","sans-serif";
        color:#1F497D;}
.MsoChpDefault
        {mso-style-type:export-only;
        font-size:10.0pt;}
@page WordSection1
        {size:612.0pt 792.0pt;
        margin:72.0pt 72.0pt 72.0pt 72.0pt;}
div.WordSection1
        {page:WordSection1;}
--></style><!--[if gte mso 9]><xml>
<o:shapedefaults v:ext="edit" spidmax="1026" />
</xml><![endif]--><!--[if gte mso 9]><xml>
<o:shapelayout v:ext="edit">
<o:idmap v:ext="edit" data="1" />
</o:shapelayout></xml><![endif]--></head><body bgcolor=white lang=EN-NZ link=blue vlink=purple><div class=WordSection1><p class=MsoNormal><span style='font-size:11.0pt;font-family:"Calibri","sans-serif";color:#1F497D'>No, the “State” and “csDestroying” elements were part of <i>my</i> framework, not the mechanism that is part of TComponent (though of course there were obvious parallels in some cases – note however that TComponent uses ComponentState, not just “State” and ControlState is introduced by the controls part of the VCL hierarchy also). <o:p></o:p></span></p><p class=MsoNormal><span style='font-size:11.0pt;font-family:"Calibri","sans-serif";color:#1F497D'><o:p> </o:p></span></p><p class=MsoNormal><span style='font-size:11.0pt;font-family:"Calibri","sans-serif";color:#1F497D'>My changes in the case that I am dragging up from the dim and distant past were not to create a replacement general purpose TInterfacedObject as such, but part of a much wider framework that happened to have at its core a class that implemented IUnknown along with a whole host of other services as part of that framework since the entire thing was interface based.<o:p></o:p></span></p><p class=MsoNormal><span style='font-size:11.0pt;font-family:"Calibri","sans-serif";color:#1F497D'><o:p> </o:p></span></p><p class=MsoNormal><span style='font-size:11.0pt;font-family:"Calibri","sans-serif";color:#1F497D'><o:p> </o:p></span></p><p class=MsoNormal><span style='font-size:11.0pt;font-family:"Calibri","sans-serif";color:#1F497D'>On a more general point, I’d say that whilst referencing “self” as an interface is an almost unavoidable part of any interface based framework, the same is not true in the destructor. Anything referenced or notified during destruction of an object that requires being passed a reference TO that object, could and most likely should, have been passed a reference to that object during construction or during some later operation.<o:p></o:p></span></p><p class=MsoNormal><span style='font-size:11.0pt;font-family:"Calibri","sans-serif";color:#1F497D'><o:p> </o:p></span></p><p class=MsoNormal><span style='font-size:11.0pt;font-family:"Calibri","sans-serif";color:#1F497D'><o:p> </o:p></span></p><p class=MsoNormal><span style='font-size:11.0pt;font-family:"Calibri","sans-serif";color:#1F497D'>However, if those other objects were holding on to those references, that would prevent the object from being destroyed in the first place.<o:p></o:p></span></p><p class=MsoNormal><span style='font-size:11.0pt;font-family:"Calibri","sans-serif";color:#1F497D'><o:p> </o:p></span></p><p class=MsoNormal><span style='font-size:11.0pt;font-family:"Calibri","sans-serif";color:#1F497D'>Another thing that is missing is a safe, common implementation of a weak reference (an interface reference that does not hold on to – i.e. does not contribute +1 toward – the reference count of the referenced object). You can use an interface reference cast as a Pointer, but the catch is that the reference must be sure that it will be notified if the referenced object is destroyed, so that it can NIL itself. Using a plain Pointer won’t do... you have to wrap it inside some object that can register for those notifications (and be sure that the object referenced will implement the required notification for the wrapper to respond to).<o:p></o:p></span></p><p class=MsoNormal><span style='font-size:11.0pt;font-family:"Calibri","sans-serif";color:#1F497D'><o:p> </o:p></span></p><p class=MsoNormal><span style='font-size:11.0pt;font-family:"Calibri","sans-serif";color:#1F497D'>Coincidentally, just this weak [sic] I found myself implementing exactly that, leveraging my TMultiCastNotify work and IOn_Destroy multicast destroy notification framework to take care of all that.<o:p></o:p></span></p><p class=MsoNormal><span style='font-size:11.0pt;font-family:"Calibri","sans-serif";color:#1F497D'><o:p> </o:p></span></p><p class=MsoNormal><span style='font-size:11.0pt;font-family:"Calibri","sans-serif";color:#1F497D'>But, that is not a general purpose solution as it requires that objects exposing interfaces that may be encapsulated in my weak reference implementation also implement IOn_Destroy, which is not built into the VCL. In fact, the VCL doesn’t have any such general purpose system (and neither should it have imho). The FreeNotification() mechanism is not supported on TObject, and neither imho should it be.<o:p></o:p></span></p><p class=MsoNormal><span style='font-size:11.0pt;font-family:"Calibri","sans-serif";color:#1F497D'><o:p> </o:p></span></p><p class=MsoNormal><span style='font-size:11.0pt;font-family:"Calibri","sans-serif";color:#1F497D'>Not every application – or indeed every object - needs these things, nor the overhead that it would incur, adding housekeeping code to the tear-down of every object.<o:p></o:p></span></p><p class=MsoNormal><span style='font-size:11.0pt;font-family:"Calibri","sans-serif";color:#1F497D'><o:p> </o:p></span></p><p class=MsoNormal><span style='font-size:11.0pt;font-family:"Calibri","sans-serif";color:#1F497D'>Most applications simply don’t need these sorts of exotica (as evidenced by the fact that these sort of facilities either don’t exist at all or took so long to be introduced into the core VCL, following the introduction of interfaces waaaaaay back in Delphi 3 – Delphi 2 did things slightly differently you may recall).<o:p></o:p></span></p><p class=MsoNormal><span style='font-size:11.0pt;font-family:"Calibri","sans-serif";color:#1F497D'><o:p> </o:p></span></p><p class=MsoNormal><span style='font-size:11.0pt;font-family:"Calibri","sans-serif";color:#1F497D'><o:p> </o:p></span></p><p class=MsoNormal><span style='font-size:11.0pt;font-family:"Calibri","sans-serif";color:#1F497D'>The very beauty of Delphi and the VCL is that we can introduce these things into the applications (or indeed the small parts of our applications) that need them, without imposing them on everything else.<o:p></o:p></span></p><p class=MsoNormal><span style='font-size:11.0pt;font-family:"Calibri","sans-serif";color:#1F497D'><o:p> </o:p></span></p><p class=MsoNormal><span style='font-size:11.0pt;font-family:"Calibri","sans-serif";color:#1F497D'>When we want the convenience of having everything to hand whether you want it or not, that’s what managed code is for. </span><span style='font-size:11.0pt;font-family:Wingdings;color:#1F497D'>J</span><span style='font-size:11.0pt;font-family:"Calibri","sans-serif";color:#1F497D'><o:p></o:p></span></p><p class=MsoNormal><span style='font-size:11.0pt;font-family:"Calibri","sans-serif";color:#1F497D'><o:p> </o:p></span></p><p class=MsoNormal><span style='font-size:11.0pt;font-family:"Calibri","sans-serif";color:#1F497D'><o:p> </o:p></span></p><p class=MsoNormal><span style='font-size:11.0pt;font-family:"Calibri","sans-serif";color:#1F497D'><o:p> </o:p></span></p><div><div style='border:none;border-top:solid #B5C4DF 1.0pt;padding:3.0pt 0cm 0cm 0cm'><p class=MsoNormal><b><span lang=EN-US style='font-size:10.0pt;font-family:"Tahoma","sans-serif";color:windowtext'>From:</span></b><span lang=EN-US style='font-size:10.0pt;font-family:"Tahoma","sans-serif";color:windowtext'> delphi-bounces@delphi.org.nz [mailto:delphi-bounces@delphi.org.nz] <b>On Behalf Of </b>Todd<br><b>Sent:</b> Wednesday, 24 November 2010 8:08 p.m.<br><b>To:</b> NZ Borland Developers Group - Delphi List<br><b>Subject:</b> Re: [DUG] How's this for inconsistent<o:p></o:p></span></p></div></div><p class=MsoNormal><o:p> </o:p></p><p class=MsoNormal><br><br><o:p></o:p></p><p class=MsoNormal><span style='font-size:11.0pt;font-family:"Calibri","sans-serif";color:#1F497D'>Yep – I remember that my fix was to set the “destructing” state indicator in a BeforeDestruction() override. This was then tested in _Release() to render it a NO-OP during execution of the destructor chain (incomplete, obviously, just to give the idea):</span><o:p></o:p></p><p class=MsoNormal><span style='font-size:11.0pt;font-family:"Calibri","sans-serif";color:#1F497D'> </span><o:p></o:p></p><p class=MsoNormal><span style='font-size:11.0pt;font-family:"Calibri","sans-serif";color:#1F497D'> Procedure BeforeDestruction;</span><o:p></o:p></p><p class=MsoNormal><span style='font-size:11.0pt;font-family:"Calibri","sans-serif";color:#1F497D'> SetState(csDestroying);</span><o:p></o:p></p><p class=MsoNormal><span style='font-size:11.0pt;font-family:"Calibri","sans-serif";color:#1F497D'> </span><o:p></o:p></p><p class=MsoNormal><span style='font-size:11.0pt;font-family:"Calibri","sans-serif";color:#1F497D'> Function _Release;</span><o:p></o:p></p><p class=MsoNormal><span style='font-size:11.0pt;font-family:"Calibri","sans-serif";color:#1F497D'> If csDestroying in State then EXIT;</span><o:p></o:p></p><p class=MsoNormal>Upon reflection, that would only work for a TComponent descendant. <o:p></o:p></p><p class=MsoNormal><span style='font-size:11.0pt;font-family:"Calibri","sans-serif";color:#1F497D'> </span><o:p></o:p></p><p class=MsoNormal><span style='font-size:11.0pt;font-family:"Calibri","sans-serif";color:#1F497D'>Nothing else needs be done, as long as any further BeforeDestruction overrides call inherited before doing their work, which they should do (in my framework I introduced another virtual to be overridden in my descendants, in case there were occasions when work was done to generate references during the destructor execution – even in your case, the FreeInstance() override is redundant I think, other than as a sanity/safety check and so could be made subject to some conditional compilation flag.</span><o:p></o:p></p><p class=MsoNormal><span style='font-size:11.0pt;font-family:"Calibri","sans-serif";color:#1F497D'> </span><o:p></o:p></p><p class=MsoNormal><span style='font-size:11.0pt;font-family:"Calibri","sans-serif";color:#1F497D'> </span><o:p></o:p></p><div><div style='border:none;border-top:solid windowtext 1.0pt;padding:3.0pt 0cm 0cm 0cm;border-color:-moz-use-text-color -moz-use-text-color'><p class=MsoNormal><b><span lang=EN-US style='font-size:10.0pt;font-family:"Tahoma","sans-serif";color:windowtext'>From:</span></b><span lang=EN-US style='font-size:10.0pt;font-family:"Tahoma","sans-serif";color:windowtext'> <a href="mailto:delphi-bounces@delphi.org.nz">delphi-bounces@delphi.org.nz</a> [<a href="mailto:delphi-bounces@delphi.org.nz">mailto:delphi-bounces@delphi.org.nz</a>] <b>On Behalf Of </b>Todd<br><b>Sent:</b> Wednesday, 24 November 2010 6:15 p.m.<br><b>To:</b> NZ Borland Developers Group - Delphi List<br><b>Subject:</b> Re: [DUG] How's this for inconsistent</span><o:p></o:p></p></div></div><p class=MsoNormal> <o:p></o:p></p><p class=MsoNormal>Actually, this would be better<br><br><span style='font-size:10.0pt'>function TamObject._Release: Integer;<br>begin<br> Result := InterlockedDecrement(FCount);<br> if (FCount = 0) then<br> begin<br> //add a reference count, incase an interface is acquired and released during destruction<br> InterlockedIncrement(FCount);<br> self.Destroy;<br> end;<br>end; </span><br><br><span style='font-size:10.0pt'>procedure TamObject.FreeInstance;<br>begin<br> //remove the reference count added in _Release</span><br><span style='font-size:10.0pt'> InterlockedDecrement(FCount);<br> assert(FCount = 0,'Destroying object with non-zero reference count');<br> inherited FreeInstance;<br>end;</span><br><br><br><o:p></o:p></p><p class=MsoNormal><span style='font-size:11.0pt;font-family:"Calibri","sans-serif";color:#1F497D'>I spotted that they fixed that a while ago – I remember having to fix the issue myself many years ago so was quite pleased to see that it was now taken care of in TInterfaceObject as a matter of course. For some reason I never noticed the omission of the same facility in the destructor. And yes, it’s a [potentially] big problem.</span><o:p></o:p></p><p class=MsoNormal><span style='font-size:11.0pt;font-family:"Calibri","sans-serif";color:#1F497D'> </span><o:p></o:p></p><p class=MsoNormal><span style='font-size:11.0pt;font-family:"Calibri","sans-serif";color:#1F497D'>I need to think about this tho... setting a fake ref count during execution of the constructor is safe enough as you know precisely when construction is done and to restore the ref count back to zero.</span><o:p></o:p></p><p class=MsoNormal><span style='font-size:11.0pt;font-family:"Calibri","sans-serif";color:#1F497D'> </span><o:p></o:p></p><p class=MsoNormal><span style='font-size:11.0pt;font-family:"Calibri","sans-serif";color:#1F497D'>Setting a fake ref count during destruction strikes me as more problematic and makes me nervous, but I can’t quite put my finger on why. It might be nothing. That doesn’t mean it can’t be fixed, only that the solution put in place for construction might not work for destruction and it wasn’t felt necessary to do any extra work for a more comprehensive solution.</span><o:p></o:p></p><p class=MsoNormal><span style='font-size:11.0pt;font-family:"Calibri","sans-serif";color:#1F497D'> </span><o:p></o:p></p><p class=MsoNormal><span style='font-size:11.0pt;font-family:"Calibri","sans-serif";color:#1F497D'> </span><o:p></o:p></p><p class=MsoNormal><span style='font-size:11.0pt;font-family:"Calibri","sans-serif";color:#1F497D'>Certainly in the case of my code where I fixed this I had specific “constructing” / “destructing” state markers (it wasn’t a general purpose interfacedobject class but a base class in a far richer framework that happened to also implement its own version of IUnknown) – I know I didn’t rely on side effects of a faked ref count.</span><o:p></o:p></p><p class=MsoNormal><span style='font-size:11.0pt;font-family:"Calibri","sans-serif";color:#1F497D'> </span><o:p></o:p></p><p class=MsoNormal><span style='font-size:11.0pt;font-family:"Calibri","sans-serif";color:#1F497D'> </span><o:p></o:p></p><div><div style='border:none;border-top:solid windowtext 1.0pt;padding:3.0pt 0cm 0cm 0cm;border-color:-moz-use-text-color'><p class=MsoNormal><b><span lang=EN-US style='font-size:10.0pt;font-family:"Tahoma","sans-serif";color:windowtext'>From:</span></b><span lang=EN-US style='font-size:10.0pt;font-family:"Tahoma","sans-serif";color:windowtext'> <a href="mailto:delphi-bounces@delphi.org.nz">delphi-bounces@delphi.org.nz</a> [<a href="mailto:delphi-bounces@delphi.org.nz">mailto:delphi-bounces@delphi.org.nz</a>] <b>On Behalf Of </b>Todd<br><b>Sent:</b> Wednesday, 24 November 2010 16:55<br><b>To:</b> NZ Borland Developers Group - Delphi List<br><b>Subject:</b> [DUG] How's this for inconsistent</span><o:p></o:p></p></div></div><p class=MsoNormal> <o:p></o:p></p><p class=MsoNormal>The Delphi developer who implemented TInterfacedObject obviously considered the case when an interface reference is grabbed during construction......<br><br><span style='font-size:10.0pt'>// Set an implicit refcount so that refcounting<br>// during construction won't destroy the object.<br>class function TInterfacedObject.NewInstance: TObject;<br>begin<br> Result := inherited NewInstance;<br> TInterfacedObject(Result).FRefCount := 1;<br>end;<br><br>procedure TInterfacedObject.AfterConstruction;<br>begin<br>// Release the constructor's implicit refcount<br> InterlockedDecrement(FRefCount);<br>end;</span><br><br>but didn't consider applying the same logic during destruction. So grabing an interface reference during destruction causes all hell to break loose, as the _Release method tries to free the object again and again recursively.<br><br><span style='font-size:10.0pt'>procedure TInterfacedObject.BeforeDestruction;<br>begin<br> if RefCount <> 0 then<br> Error(reInvalidPtr);<br>end;</span><br><br><span style='font-size:10.0pt'>function TInterfacedObject._Release: Integer;<br>begin<br> Result := InterlockedDecrement(FRefCount);<br> if Result = 0 then<br> Destroy;<br>end;</span><br><br>Todd.<o:p></o:p></p><pre> <o:p></o:p></pre><pre> <o:p></o:p></pre><pre>_______________________________________________<o:p></o:p></pre><pre>NZ Borland Developers Group - Delphi mailing list<o:p></o:p></pre><pre>Post: <a href="mailto:delphi@delphi.org.nz">delphi@delphi.org.nz</a><o:p></o:p></pre><pre>Admin: <a href="http://delphi.org.nz/mailman/listinfo/delphi">http://delphi.org.nz/mailman/listinfo/delphi</a><o:p></o:p></pre><pre>Unsubscribe: send an email to <a href="mailto:delphi-request@delphi.org.nz">delphi-request@delphi.org.nz</a> with Subject: unsubscribe<o:p></o:p></pre><p class=MsoNormal> <o:p></o:p></p><pre><o:p> </o:p></pre><pre><o:p> </o:p></pre><pre>_______________________________________________<o:p></o:p></pre><pre>NZ Borland Developers Group - Delphi mailing list<o:p></o:p></pre><pre>Post: <a href="mailto:delphi@delphi.org.nz">delphi@delphi.org.nz</a><o:p></o:p></pre><pre>Admin: <a href="http://delphi.org.nz/mailman/listinfo/delphi">http://delphi.org.nz/mailman/listinfo/delphi</a><o:p></o:p></pre><pre>Unsubscribe: send an email to <a href="mailto:delphi-request@delphi.org.nz">delphi-request@delphi.org.nz</a> with Subject: unsubscribe<o:p></o:p></pre><p class=MsoNormal><o:p> </o:p></p></div></body></html>