www.digitalmars.com         C & C++   DMDScript  

digitalmars.D - clear()

reply "Marco Leise" <Marco.Leise gmx.de> writes:
Can someone clarify things for me? So I use .clear() as usual to clear my  
arrays and associative arrays. But a post by Jonathan M Davis in D.learn  
made me realize that same name is used to call a destructor on an object  
and now I wonder if clear() was ever supposed to be called on associative  
arrays and what the official way is to reset the contents of an  
associative array (except for solutions containing null and foreach :) ).

clear() is well established and known to set the container length to 0  
(releasing references and destroying owned objects, often keeping the  
capacity) as seen in these references of container types in various  
languages:
   (C++ STL) http://www.cplusplus.com/reference/stl/vector/clear/
   (.NET)    http://msdn.microsoft.com/en-us/library/dwb5h52a.aspx
   (Pascal)   
http://www.freepascal.org/docs-html/rtl/classes/tlist.clear.html
   (Ruby)    http://www.ruby-doc.org/core/classes/Array.html#M000263

Is there a reason why the method that calls the destructor hasn't been  
called 'deinit', 'destruct', 'invalidate' or 'destroy' instead?

And are these bug reports in fact invalid as per specification of clear() ?
http://www.digitalmars.com/d/archives/digitalmars/D/bugs/Issue_5816_New_clear_breaks_associative_array_29122.html
http://www.digitalmars.com/d/archives/digitalmars/D/bugs/Issue_5683_New_Calling_.clear_on_a_fresh_associative_array_causes_subsequent_segfault_28632.html

I'm confused :p

- Marco
Sep 11 2011
next sibling parent reply Michel Fortin <michel.fortin michelf.com> writes:
On 2011-09-11 10:23:21 +0000, "Marco Leise" <Marco.Leise gmx.de> said:

 Is there a reason why the method that calls the destructor hasn't been  
 called 'deinit', 'destruct', 'invalidate' or 'destroy' instead?

Probably to confuse people.
 And are these bug reports in fact invalid as per specification of clear() ?
 http://www.digitalmars.com/d/archives/digitalmars/D/bugs/Issue_5816_New_clear_breaks_associative_array_29122.html

Seems
 

confusing people.
 I'm confused :p

See, it works! 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. :-( -- Michel Fortin michel.fortin michelf.com http://michelf.com/
Sep 12 2011
parent reply Michel Fortin <michel.fortin michelf.com> writes:
On 2011-09-12 11:37:20 +0000, "Steven Schveighoffer" 
<schveiguy yahoo.com> said:

 On Mon, 12 Sep 2011 07:12:19 -0400, Michel Fortin  
 <michel.fortin michelf.com> wrote:
 
 On 2011-09-11 10:23:21 +0000, "Marco Leise" <Marco.Leise gmx.de> 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'… '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). -- Michel Fortin michel.fortin michelf.com http://michelf.com/
Sep 12 2011
parent reply Michel Fortin <michel.fortin michelf.com> writes:
On 2011-09-12 20:04:05 +0000, "Steven Schveighoffer" 
<schveiguy yahoo.com> said:

 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?

struct S { disable this(); }
 I hated having clear call the default constructor.

… because you use 'clear' to release resources. Which makes sense, but goes contrary to expectations for something called 'clear'. What I am saying is that 'clear' shouldn't be used to release resources, something else should be used for that.
 I think that's
 entirely the wrong thing to do.  clear + deallocate replaces delete, wit h
 clear being the finalization of the data.

Well, if you really wanted clear + deallocate to replace delete (regardless of the suitability of the name), don't make it so it looks like you can reuse the object/struct afterward. Saying it is assigning the 'init' state makes people believe the object will still be in a usable state although actually there is no guaranty of that, and that's true for a struct too (as shown above). Also, if 'clear' is meant to replace 'delete', it should give an error when called on non-GC memory because there's no way you can prevent the destructor from being called a second time otherwise. -- Michel Fortin michel.fortin michelf.com http://michelf.com/
Sep 12 2011
next sibling parent Andrei Alexandrescu <SeeWebsiteForEmail erdani.org> writes:
On 09/12/2011 04:36 PM, Michel Fortin wrote:
 On 2011-09-12 20:04:05 +0000, "Steven Schveighoffer"
 <schveiguy yahoo.com> said:

 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?

struct S { disable this(); }

Nope, the way Walter designed the feature, when such a struct is a member, it will have opAssign called against an object initialized with .init. Generally I find this discussion difficult to get into. So you don't like the name clear() and you don't like the behavior of clear(). (Also, you seem to consider calling the destructor several times an impossibility. Why?) Anyhow, any chance to post a condensed list of issues as you see them along with proposed fixes? Thanks, Andrei
Sep 12 2011
prev sibling parent reply sclytrack <sclytrack iq87.com> writes:
Rename "clear" to "blank" in D version 3.

Like blank a CD it is ready for writing but not ready for use. It is ready for
use
after you have burned something on it. Unless you consider burning a CD using
it.

blank();
Sep 13 2011
parent reply Alix Pexton <alix.DOT.pexton gmail.DOT.com> writes:
On 13/09/2011 17:05, sclytrack wrote:
 Rename "clear" to "blank" in D version 3.

 Like blank a CD it is ready for writing but not ready for use. It is ready for
use
 after you have burned something on it. Unless you consider burning a CD using
it.

 blank();

wipe(); //?? A...
Sep 13 2011
parent Dmitry Olshansky <dmitry.olsh gmail.com> writes:
On 14.09.2011 1:12, Alix Pexton wrote:
 On 13/09/2011 17:05, sclytrack wrote:
 Rename "clear" to "blank" in D version 3.

 Like blank a CD it is ready for writing but not ready for use. It is
 ready for use
 after you have burned something on it. Unless you consider burning a
 CD using it.

 blank();

wipe(); //?? A...

my favorite still: nuke(x); //now it's obvious x is not valid ;) -- Dmitry Olshansky
Sep 13 2011
prev sibling next sibling parent "Steven Schveighoffer" <schveiguy yahoo.com> writes:
On Mon, 12 Sep 2011 07:12:19 -0400, Michel Fortin  
<michel.fortin michelf.com> wrote:

 On 2011-09-11 10:23:21 +0000, "Marco Leise" <Marco.Leise gmx.de> 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. -Steve
Sep 12 2011
prev sibling next sibling parent "Steven Schveighoffer" <schveiguy yahoo.com> writes:
On Mon, 12 Sep 2011 15:43:13 -0400, Michel Fortin  =

<michel.fortin michelf.com> wrote:

 On 2011-09-12 11:37:20 +0000, "Steven Schveighoffer"  =

 <schveiguy yahoo.com> said:

 On Mon, 12 Sep 2011 07:12:19 -0400, Michel Fortin   =


 <michel.fortin michelf.com> wrote:

 On 2011-09-11 10:23:21 +0000, "Marco Leise" <Marco.Leise gmx.de> sai=



  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. Actual=



 no, the worse part is probably  that it's inside module 'object', th=



 only module imported by default  everywhere, so you can't even escap=



 the confusion by not importing its  module. :-(



 relegated to only be "call the destructor" (in fact, I use clear as a=


 member function in my dcollections library, which probably adds to th=


 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 destructo=

 doesn't expect this. The destructor will be called twice when you use =

 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 an=

 write programs that'll break later when the implementation behind an A=

 changes. Remember that this problem couldn't happen with 'delete'=E2=80=

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 scop= e = 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  =

 the GC, keeping things memory-safe. There's absolutely no point in  =

 reinstating the original 'init' bits if what you want is to destroy th=

 object. 'delete' only works with memory allocated on the heap, not sta=

 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 th=

 destructor, reinstating the 'init' bits, then calling constructor agai=

 if necessary. It could be safe to call on stack variables, and it coul=

 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, wit= h = clear being the finalization of the data. If you want to reallocate, yo= u = can always reassign the reference to a default-constructed object. -Steve
Sep 12 2011
prev sibling next sibling parent "Steven Schveighoffer" <schveiguy yahoo.com> writes:
On Mon, 12 Sep 2011 17:36:09 -0400, Michel Fortin  =

<michel.fortin michelf.com> wrote:

 On 2011-09-12 20:04:05 +0000, "Steven Schveighoffer"  =

 <schveiguy yahoo.com> said:

 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?

struct S { disable this(); }

That is a brand new feature that was added after clear was implemented, = = and I'm not sure of the semantics yet. I'd suspect that clear probably = = should be statically disallowed if no default ctor is allowed. If what Andrei says is true, however, then assigning to .init is still = feasible, and should be able to be destructed.
 I hated having clear call the default constructor.

=E2=80=A6 because you use 'clear' to release resources. Which makes se=

 goes contrary to expectations for something called 'clear'. What I am =

 saying is that 'clear' shouldn't be used to release resources, somethi=

 else should be used for that.

I agree the name clear isn't ideal. I don't think we can change it now,= = though. But we need *something* that releases resources without reacquiring them= . = The case for reinitializing resources after releasing them is pretty = uncommon. And in those cases, the object itself can support that, we = don't need a language solution.
 I think that's
 entirely the wrong thing to do.  clear + deallocate replaces delete, =


 wit h
 clear being the finalization of the data.

Well, if you really wanted clear + deallocate to replace delete =

 (regardless of the suitability of the name), don't make it so it looks=

 like you can reuse the object/struct afterward. Saying it is assigning=

 the 'init' state makes people believe the object will still be in a  =

 usable state although actually there is no guaranty of that, and that'=

 true for a struct too (as shown above).

You can only reuse the object after if it's a struct. If it's an object= , = you cannot. I think that's pretty much universal (does not depend on th= e = implementation of the struct/class). I think the point of clear is, you are deallocating, and no longer using= = that item. Using it afterwards is not supported without reinitializatio= n.
 Also, if 'clear' is meant to replace 'delete', it should give an error=

 when called on non-GC memory because there's no way you can prevent th=

 destructor from being called a second time otherwise.

Clear is not meant to replace delete, clear + deallocate is. The notion that the library provides a mechanism to do what clear does = *without* deallocation is a new concept. That concept extends very well= = into non-heap-based types. -Steve
Sep 13 2011
prev sibling parent "Simen Kjaeraas" <simen.kjaras gmail.com> writes:
On Tue, 13 Sep 2011 23:18:57 +0200, Dmitry Olshansky  
<dmitry.olsh gmail.com> wrote:

 On 14.09.2011 1:12, Alix Pexton wrote:
 On 13/09/2011 17:05, sclytrack wrote:
 Rename "clear" to "blank" in D version 3.

 Like blank a CD it is ready for writing but not ready for use. It is
 ready for use
 after you have burned something on it. Unless you consider burning a
 CD using it.

 blank();

wipe(); //?? A...

my favorite still: nuke(x); //now it's obvious x is not valid ;)

That's actually kinda nice. Unlikely to be used for much else, intention very clear, and the name is short and easy to remember. Not to mention, it's a crowd-pleaser. -- Simen
Sep 14 2011