Jump to page: 1 2
Thread overview
clear()
Sep 11, 2011
Marco Leise
Sep 12, 2011
Michel Fortin
Sep 12, 2011
Michel Fortin
Sep 12, 2011
Michel Fortin
Sep 13, 2011
sclytrack
Sep 13, 2011
Alix Pexton
Sep 13, 2011
Dmitry Olshansky
Sep 14, 2011
Simen Kjaeraas
September 11, 2011
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
September 12, 2011
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
http://www.digitalmars.com/d/archives/digitalmars/D/bugs/Issue_5683_New_Calling_.clear_on_a_fresh_associative_array_causes_subsequent_segfault_28632.html

Seems 
> 
like they are indeed invalid. Clear is working as intended, and is 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/

September 12, 2011
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
September 12, 2011
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/

September 12, 2011
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> 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
September 12, 2011
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/

September 12, 2011
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
September 13, 2011
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.
>
> … 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 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's 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 the 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 reinitialization.

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

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
September 13, 2011
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();
September 13, 2011
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...
« First   ‹ Prev
1 2