www.digitalmars.com         C & C++   DMDScript  

digitalmars.D - Documentation of object.destroy

reply Johan Engelen <j j.nl> writes:
Hi all,

Link: https://dlang.org/library/object/destroy.html

The documentation says "Destroys the given object and puts it in 
an invalid state. " However, this is not (strictly) true. What 
destroy() does is overwrite the object with T.init (or zeros), 
and we should explicitly mention that. Also, the documentation 
states "that it [the object destroyed] no longer references any 
other objects.", which is wrong as this code shows:

```
__gshared int global;
struct S {
     int* pint = &global;
}
void main() {
     S s;
     int i;
     s.pint = &i;
     assert(s.pint != &global);
     destroy(s);
     assert(s.pint != &global); // fails
}
```
https://run.dlang.io/is/SFbxNm

How about:
"Destroys the given object `obj` and puts `obj` in its `T.init` 
state. This function used to destroy an object such that any 
cleanup by the destructor or finalizer is done, and such that 
`obj` no longer references any other objects (unless `T.init` 
references other objects). This function does not initiate a GC 
cycle nor free any GC memory."

regards,
   Johan
Jan 02 2018
next sibling parent reply Temtaime <temtaime gmail.com> writes:
On Tuesday, 2 January 2018 at 13:58:49 UTC, Johan Engelen wrote:
 Hi all,

 Link: https://dlang.org/library/object/destroy.html

 The documentation says "Destroys the given object and puts it 
 in an invalid state. " However, this is not (strictly) true. 
 What destroy() does is overwrite the object with T.init (or 
 zeros), and we should explicitly mention that. Also, the 
 documentation states "that it [the object destroyed] no longer 
 references any other objects.", which is wrong as this code 
 shows:

 ```
 __gshared int global;
 struct S {
     int* pint = &global;
 }
 void main() {
     S s;
     int i;
     s.pint = &i;
     assert(s.pint != &global);
     destroy(s);
     assert(s.pint != &global); // fails
 }
 ```
 https://run.dlang.io/is/SFbxNm

 How about:
 "Destroys the given object `obj` and puts `obj` in its `T.init` 
 state. This function used to destroy an object such that any 
 cleanup by the destructor or finalizer is done, and such that 
 `obj` no longer references any other objects (unless `T.init` 
 references other objects). This function does not initiate a GC 
 cycle nor free any GC memory."

 regards,
   Johan
Why not zerofy the object ?
Jan 02 2018
parent reply Johan Engelen <j j.nl> writes:
On Tuesday, 2 January 2018 at 14:22:06 UTC, Temtaime wrote:
 Why not zerofy the object ?
Please keep the discussion on the topic of documentation, thanks. -Johan
Jan 02 2018
parent Temtaime <temtaime gmail.com> writes:
On Tuesday, 2 January 2018 at 14:39:52 UTC, Johan Engelen wrote:
 On Tuesday, 2 January 2018 at 14:22:06 UTC, Temtaime wrote:
 Why not zerofy the object ?
Please keep the discussion on the topic of documentation, thanks. -Johan
Documentation does not correspond with the actual behavior, so fill a PR and that's all. Then why even this topic is created ?
Jan 02 2018
prev sibling next sibling parent 12345swordy <alexanderheistermann gmail.com> writes:
On Tuesday, 2 January 2018 at 13:58:49 UTC, Johan Engelen wrote:
 Hi all,

 Link: https://dlang.org/library/object/destroy.html

 [...]
Destroy calls the finalized function. (Which last time I check it's still a c function)
Jan 02 2018
prev sibling next sibling parent reply Mike Franklin <slavo5150 yahoo.com> writes:
On Tuesday, 2 January 2018 at 13:58:49 UTC, Johan Engelen wrote:

 How about:
 "Destroys the given object `obj` and puts `obj` in its `T.init` 
 state. This function used to destroy an object such that any 
 cleanup by the destructor or finalizer is done, and such that 
 `obj` no longer references any other objects (unless `T.init` 
 references other objects). This function does not initiate a GC 
 cycle nor free any GC memory."
I think you meant "This function *is* used..." I suggest the following: Calls `obj`'s destructor and sets `obj` to its default initial state, `T.init`. This function does not initiate a GC cycle nor does it free any GC memory. Mike
Jan 02 2018
parent Petar Kirov [ZombineDev] <petar.p.kirov gmail.com> writes:
On Tuesday, 2 January 2018 at 15:13:46 UTC, Mike Franklin wrote:
 [..]

 I suggest the following:

 Calls `obj`'s destructor and sets `obj` to its default initial 
 state, `T.init`.  This function does not initiate a GC cycle 
 nor does it free any GC memory.

 Mike
+1
Jan 02 2018
prev sibling parent reply Steven Schveighoffer <schveiguy yahoo.com> writes:
On 1/2/18 8:58 AM, Johan Engelen wrote:
 Hi all,
 
 Link: https://dlang.org/library/object/destroy.html
 
 The documentation says "Destroys the given object and puts it in an 
 invalid state. " However, this is not (strictly) true. What destroy() 
 does is overwrite the object with T.init (or zeros), and we should 
 explicitly mention that. Also, the documentation states "that it [the 
 object destroyed] no longer references any other objects.", which is 
 wrong as this code shows:
It does something different depending on the type: Objects: calls rt_finalize on the object, which calls the dtor, deletes the monitor, rewrites the init value to the object, and THEN zeroes the vtable ptr. This last step makes it inoperable for anyone still holding a pointer to the object. This is why I think the docs are written the way they are. Interfaces: If this is a D object, casts to Object and calls destroy on it. Structs: calls the dtor (if it exists), destroys recursively all the data members of the struct, and then initializes the data to it's init state. Everything else: overwrites with the init data. More explicitly, destroying a pointer simply sets it to null, and does not destroy what it points at. I would actually recommend ddocing each of the overloads of destroy individually instead of lumping them together, identifying what happens with each one. -Steve
Jan 02 2018
next sibling parent reply jmh530 <john.michael.hall gmail.com> writes:
On Tuesday, 2 January 2018 at 17:16:54 UTC, Steven Schveighoffer 
wrote:
 It does something different depending on the type:

 Objects: calls rt_finalize on the object, which calls the dtor, 
 deletes the monitor, rewrites the init value to the object, and 
 THEN zeroes the vtable ptr. This last step makes it inoperable 
 for anyone still holding a pointer to the object. This is why I 
 think the docs are written the way they are.
What's the monitor do? I see that in the ABI documentation, but it doesn't really explain it...
Jan 02 2018
next sibling parent Steven Schveighoffer <schveiguy yahoo.com> writes:
On 1/2/18 3:07 PM, jmh530 wrote:
 On Tuesday, 2 January 2018 at 17:16:54 UTC, Steven Schveighoffer wrote:
 It does something different depending on the type:

 Objects: calls rt_finalize on the object, which calls the dtor, 
 deletes the monitor, rewrites the init value to the object, and THEN 
 zeroes the vtable ptr. This last step makes it inoperable for anyone 
 still holding a pointer to the object. This is why I think the docs 
 are written the way they are.
What's the monitor do? I see that in the ABI documentation, but it doesn't really explain it...
The monitor is used to lock any object for synchronization. It's allocated on demand. https://dlang.org/spec/class.html#synchronized-classes -Steve
Jan 02 2018
prev sibling parent Ola Fosheim =?UTF-8?B?R3LDuHN0YWQ=?= <ola.fosheim.grostad gmail.com> writes:
On Tuesday, 2 January 2018 at 20:07:11 UTC, jmh530 wrote:
 What's the monitor do? I see that in the ABI documentation, but 
 it doesn't really explain it...
A monitor queues/schedules processes that are calling methods of an object so that only one process is executing methods on a single object at any given point in time. https://en.wikipedia.org/wiki/Monitor_(synchronization)
Jan 02 2018
prev sibling next sibling parent Johan Engelen <j j.nl> writes:
On Tuesday, 2 January 2018 at 17:16:54 UTC, Steven Schveighoffer 
wrote:
 I would actually recommend ddocing each of the overloads of 
 destroy individually instead of lumping them together, 
 identifying what happens with each one.
I first wrote an extra one for just structs, but then decided to keep it all combined for all, to try and make things easier to remember. But maybe the differences are too large indeed. -Johan
Jan 02 2018
prev sibling parent Johan Engelen <j j.nl> writes:
On Tuesday, 2 January 2018 at 17:16:54 UTC, Steven Schveighoffer 
wrote:
 On 1/2/18 8:58 AM, Johan Engelen wrote:
 Hi all,
 
 Link: https://dlang.org/library/object/destroy.html
Much obliged to anyone doing the effort of fixing and improving the doc. I think Steven made a nice start. I added some comments below.
 It does something different depending on the type:

 Objects: calls rt_finalize on the object, which calls the dtor, 
 deletes the monitor, rewrites the init value to the object, and 
 THEN zeroes the vtable ptr. This last step makes it inoperable 
 for anyone still holding a pointer to the object. This is why I 
 think the docs are written the way they are.
rt_finalize is an implementation detail and shouldn't be in the docs here. Important to mention the re-init _and_ the obj still being in invalid state (vtable is implementation detail and may be left out).
 Interfaces: If this is a D object, casts to Object and calls 
 destroy on it.

 Structs: calls the dtor (if it exists), destroys recursively 
 all the data members of the struct, and then initializes the 
 data to it's init state.

 Everything else: overwrites with the init data. More 
 explicitly, destroying a pointer simply sets it to null, and 
 does not destroy what it points at.
I find "does not destroy what it points at" important to mention. (perhaps even with an explicit "you have to dereference the pointer to destroy what it points at"). Thanks, Cheers, Johan
Jan 02 2018