On Mon, 12 Sep 2011 15:43:13 -0400, Michel Fortin <[email protected]> wrote:

On 2011-09-12 11:37:20 +0000, "Steven Schveighoffer" <[email protected]> said:

On Mon, 12 Sep 2011 07:12:19 -0400, Michel Fortin <[email protected]> wrote:

On 2011-09-11 10:23:21 +0000, "Marco Leise" <[email protected]> said:
Enough sarcasm. If I recall, Andrei liked the name 'clear' and was unsympathetic to the arguments that it'd be confusing. 'clear' is explained in TDPL and Andrei doesn't like to break his book, so we might be stuck with that mess for while. But I think it's clear by now that that 'clear' is confusing and dangerous: it will work with certain types and completely blow up with others depending on implementation details of the type (calling the destructor twice, it's insane!). And the name just make it sounds like it's something pretty normal to do, which is probably the worse part of it. Actually no, the worse part is probably that it's inside module 'object', the only module imported by default everywhere, so you can't even escape the confusion by not importing its module. :-(
While I share your sentiment that clear is too useful a term to be relegated to only be "call the destructor" (in fact, I use clear as a member function in my dcollections library, which probably adds to the confusion), I still think that the function should work. What types does it "blow up" on? What types does it call the destructor twice? I'd like to fix these.

It can "blow up" when the destructor is called twice and the destructor doesn't expect this. The destructor will be called twice when you use it on a struct variable on the stack. You'll probably say it shouldn't be used on stack variables, but if something work, especially if it looks pretty and appropriate like 'clear' does, people will use it anyway and write programs that'll break later when the implementation behind an API changes. Remember that this problem couldn't happen with 'delete'…

I'm not sure that's valid. If you can declare a struct, you can declare an uninitialized struct, whose destructor *will* be called when the scope exits.

How does an author of a struct "not expect" the destructor to be called on an .init version of itself? Isn't that an error? Do you have a counter-case?


'clear' conflates two things: restoring the object to its pristine state, and releasing resources. It does succeed at releasing resources, but only because it reaches half of the former goal. I think it'd be much wiser to have two different functions for these two concepts.

I think 'delete' is the one that should be tasked with releasing resources. Just change 'delete' so it calls the destructor, wipes all the bits, but keep the memory block alive so it gets collected later by the GC, keeping things memory-safe. There's absolutely no point in reinstating the original 'init' bits if what you want is to destroy the object. 'delete' only works with memory allocated on the heap, not stack variables, not memory allocated elsewhere, so it's easy to make sure destructors don't get called twice because that's a bit in the GC's block flags.

Then you can make 'clear' a function that actually does what people expects it to do: restore the object to its pristine state: calling the destructor, reinstating the 'init' bits, then calling constructor again if necessary. It could be safe to call on stack variables, and it could fail if the default constructor is disabled (like in NotNull!T).

I hated having clear call the default constructor. I think that's entirely the wrong thing to do. clear + deallocate replaces delete, with clear being the finalization of the data. If you want to reallocate, you can always reassign the reference to a default-constructed object.

-Steve

Reply via email to