[Was out of town a few days. Hope this isn't too stale. Comments interleaved.]
At 11:02 AM 4/8/2004, John Elliot wrote (in part) >>The sample code shows one of the gazillion ways it's possible to cause an >>object to be in an "illegal" (a.k.a. undefined or unexpected) state [snip] > >What state does an object whose constructor throws an exception need to >guarantee that it is in? Either the "I am able to work correctly despite my initialization having failed" state, or the "I did not pass a reference to myself to another object before completing my initialization" state. >>The fact that an object exists during execution of its constructor [snip] > >Constructor is a bad word. I agree with the person who commented on this >thread about 'initialization'. The runtime manages construction on the >managed heap all we do is conduct initialization in the 'constructor'. Agreed -- "initializer" would be a better word, but MS called it "constructor" sp we're stuck with that term. >>The fact that an object exists until it's garbage collected (whether or not >>an exception is raised in the constructor, or in any other method) is the >>way things work in .NET. > >Sure. And the GC works to release objects for you when you no longer >reference them. If you pass a reference to 'this' from a constructor >that throws an exception then you're paving the way for a subtle (and >possibly very problematic) bug to occur, and you've quite possibly >created a memory leak. I think that my point was quite valid. I was trying to make the point that passing the 'this' of an object that's in an illegal state can cause any kind of bug. You need to prevent your objects from being in illegal states, particularly if you're going to pass references to such objects around (thus prolonging the bad objects' lifetimes); otherwise you have a bug in your code. I don't know that I consider this to be any more of a "subtle" bug than any other bug that involves failing to specifically acknowledge that some object states "can't happen" and that letting an object (or group of coordinating objects) get into states that "can't happen" is a bug. (When isn't a bug "subtle"? It could defined as "one I've not seen myself, or discussed, before" so now this isn't a "subtle bug" any more, because we're discussing it <g>.) >>The fact that it's possible to store a reference to an object that is in an >>illegal state, and thus prolong the lifetime of that "bad" object by >>preventing an object from being GCd, doesn't surprise anyone -- does it? > >It might surprise someone who received an exception from a constructor >and hadn't realised that even though the constructor didn't return a >reference to the new object the object was still allocated on the heap. >I'll admit to being surprised. The surprise should not be that the object was allocated, but that somehow a reference to it exists even though the code that called the "constructor" wasn't able to store a reference due to the exception. And that surprise ([subtle] bug) was caused by the object passing a reference to itself even though it wasn't fully initialized (and thus is possibly in a "bad" state). >>If you don't work carefully to avoid problems with an object's state [snip] > >That's a pretty arrogant tone you've got there. And I thought I was >arrogant. Pfft.. :) Agreed, and it wasn't really intended to be rude; glad that you saw fit to put the :) in there. I think it's just a question of where one draws the line between "bug" and "subtle bug." >I have never had anyone warn me about passing a reference to 'this' from >a constructor that might throw to another instance. I thought my point >that the way InitializeComponent() is called first in a WinForms >constructor and then proceeds to hook up event handlers before the rest >of your code executes (even recommending that it is the first line in >the constructor) was fairly insightful. Who knows what the WinForms >architecture might then be doing to cause that reference to remain in >scope even after initialization fails. Say an event on a static object >is hooked for example? I'm pretty sure there heaps of bugs out in the >world right now because someone failed to realise this (possibly even in >the BCL, or WinForms architecture). > >I'm pretty sure that regardless of statements that indicate that >'dispose' is an 'optional' call there are parts of the WinForms >architecture that rely on it, and if I can't get a reference to a >constructed object yet the framework has one stashed in a delegate >somewhere, then I've got a memory leak. I have to think about this a bit to see all the possibilities. What object hasn't been properly initialized when a form's InitializeComponent throws? What object exists that holds a delegate-based reference to a not-constructed object? >What's the go with the Disposed event on Component by the way? Can you >rely on this being raised? What happens if the component goes out of >scope and gets finalized? Is Dispose a required call for Component? I don't think there's anything "required" by CLR, but there is by convention. Doesn't a Component call Dispose on all its contained controls during its Dispose, unless you override its Dispose with a version that doesn't do that? >John. J. Merrill / Analytical Software Corp =================================== This list is hosted by DevelopMentorŪ http://www.develop.com Some .NET courses you may be interested in: NEW! Guerrilla ASP.NET, 17 May 2004, in Los Angeles http://www.develop.com/courses/gaspdotnetls View archives and manage your subscription(s) at http://discuss.develop.com