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