Thread overview | |||||||||||||||||||||||||||||||||||||
---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
|
July 26, 2017 Destructors vs. Finalizers | ||||
---|---|---|---|---|
| ||||
Regarding the issue with `destroy` not being @nogc, I my understanding is it comes down to `rt_finalize` not being @nogc. I haven't dug too deeply into the discussions around it, but I'm wondering if it's possible to separate the concept of destruction from finalization in the implementation? Externally, we can do it with the existing language: class { ~this() {} // Finalizer ~this @nogc {} // Destructor } Internally, the runtime will treat each differently. an rt_destruct would call all every __dtor in a hierarchy and rt_finalize would be changed to call every __finalizer (a new addition) in a hierarchy. When cleaning up, the GC will ensure that all destructors are run where they exist, followed by all finalizers. And destroy would be changed to call rt_destruct instead of rt_finalize. Thoughts? |
July 26, 2017 Re: Destructors vs. Finalizers | ||||
---|---|---|---|---|
| ||||
Posted in reply to Mike Parker | On Wednesday, 26 July 2017 at 02:58:00 UTC, Mike Parker wrote:
>
> Internally, the runtime will treat each differently. an rt_destruct would call all every __dtor in a hierarchy and rt_finalize would be changed to call every __finalizer (a new addition) in a hierarchy. When cleaning up, the GC will ensure that all destructors are run where they exist, followed by all finalizers. And destroy would be changed to call rt_destruct instead of rt_finalize.
>
> Thoughts?
And an important bit I left out -- destroy would still call rt_finalize if no destructor is present, which would preserve current behavior.
|
July 26, 2017 Re: Destructors vs. Finalizers | ||||
---|---|---|---|---|
| ||||
Posted in reply to Mike Parker | On Wednesday, 26 July 2017 at 02:58:00 UTC, Mike Parker wrote: > Regarding the issue with `destroy` not being @nogc, I my understanding is it comes down to `rt_finalize` not being @nogc. I haven't dug too deeply into the discussions around it, but I'm wondering if it's possible to separate the concept of destruction from finalization in the implementation? Possible, yes, and I agree that separating destruction (deterministic end of object lifetime) and finalization (GC collection caused end of object lifetime) for classes is something we should do. > > Externally, we can do it with the existing language: > > class { > ~this() {} // Finalizer > > ~this @nogc {} // Destructor > } As class destructors (in contrast to class finalizers) are then called exclusively in a deterministic fashion, there's no reason to forbid them from allocating using the GC, so I don't think using the @nogc attribute would be appropriate; I would much rather see another attribute in the likes of @disable, e.g. @deterministic, so --- ~this() {} // Finalizer ~this() @nogc {} // Finalizer ~this @deterministic {} // Destructor ~this @nogc @deterministic {} // Destructor } --- > > Internally, the runtime will treat each differently. an rt_destruct would call all every __dtor in a hierarchy As long as finalizers are then not part of __dtor. > and rt_finalize would be changed to call every __finalizer (a new addition) in a hierarchy. > When cleaning up, the GC will ensure that all destructors are run where they exist, followed by all finalizers. Having the GC directly call destructors defeats the point of separating them from finalizers in the first place: If a destructor should be run on GC finalication, the finalizer must manually call the destructor (using e.g. `destroy`). The GC must *never* call destructors automatically after splitting off finalizers, because that would turn destructors back into finalizers. > And destroy would be changed to call rt_destruct instead of rt_finalize. Yes, that would then be the correct behaviour for `destroy`. |
July 26, 2017 Re: Destructors vs. Finalizers | ||||
---|---|---|---|---|
| ||||
Posted in reply to Mike Parker | On Wednesday, 26 July 2017 at 02:58:00 UTC, Mike Parker wrote:
> When cleaning up, the GC will ensure that all destructors are run where they exist, followed by all finalizers. And destroy would be changed to call rt_destruct instead of rt_finalize.
>
> Thoughts?
I don't get the distinction between destructors and "finalizers" but imho the problem is very much that the GC is calling ~this.
|
July 26, 2017 Re: Destructors vs. Finalizers | ||||
---|---|---|---|---|
| ||||
Posted in reply to Guillaume Piolat | On Wednesday, 26 July 2017 at 12:19:15 UTC, Guillaume Piolat wrote:
>
> I don't get the distinction between destructors and "finalizers" but imho the problem is very much that the GC is calling ~this.
Destructors are deterministic, finalizers are not. At least, that's how I understand the terms are commonly used.
|
July 26, 2017 Re: Destructors vs. Finalizers | ||||
---|---|---|---|---|
| ||||
Posted in reply to Guillaume Piolat | On 7/26/17 8:19 AM, Guillaume Piolat wrote:
> On Wednesday, 26 July 2017 at 02:58:00 UTC, Mike Parker wrote:
>> When cleaning up, the GC will ensure that all destructors are run where they exist, followed by all finalizers. And destroy would be changed to call rt_destruct instead of rt_finalize.
>>
>> Thoughts?
>
> I don't get the distinction between destructors and "finalizers" but imho the problem is very much that the GC is calling ~this.
In D, the difference is when the thing is called. If it's called deterministically, either by function or by the compiler, then you have a lot more flexibility. If it's by the GC, it can be out of order with regards to your members, it could be on a different thread than the one that owned it, etc.
Regarding the OP, I think we really should strive to have something to fix this issue.
A poor-mans distinction could be done by checking whether the GC is currently the one destroying (a flag is available, but isn't publicly accessible), though that could get expensive.
-Steve
|
July 26, 2017 Re: Destructors vs. Finalizers | ||||
---|---|---|---|---|
| ||||
Posted in reply to Moritz Maxeiner | On Wednesday, 26 July 2017 at 09:29:15 UTC, Moritz Maxeiner wrote: > As class destructors (in contrast to class finalizers) are then called exclusively in a deterministic fashion, there's no reason to forbid them from allocating using the GC, so I don't think using the @nogc attribute would be appropriate; I would much rather see another attribute in the likes of @disable, e.g. @deterministic, so > --- > ~this() {} // Finalizer > ~this() @nogc {} // Finalizer > ~this @deterministic {} // Destructor > ~this @nogc @deterministic {} // Destructor > } Yeah, this brings with it more flexibility. I'd prefer to avoid adding a new attribute for it, but this looks more interesting. >> When cleaning up, the GC will ensure that all destructors are run where they exist, followed by all finalizers. > > Having the GC directly call destructors defeats the point of separating them from finalizers in the first place: Indeed! Let's pretend I didn't write that. |
July 26, 2017 Re: Destructors vs. Finalizers | ||||
---|---|---|---|---|
| ||||
Posted in reply to Steven Schveighoffer | On Wednesday, 26 July 2017 at 12:43:27 UTC, Steven Schveighoffer wrote: > > Regarding the OP, I think we really should strive to have something to fix this issue. > > A poor-mans distinction could be done by checking whether the GC is currently the one destroying (a flag is available, but isn't publicly accessible), though that could get expensive. That's essentially what Guillaume's "GC-proof resource class" idiom does now. https://p0nce.github.io/d-idioms/#GC-proof-resource-class |
July 26, 2017 Re: Destructors vs. Finalizers | ||||
---|---|---|---|---|
| ||||
Posted in reply to Mike Parker | On Wednesday, 26 July 2017 at 12:55:17 UTC, Mike Parker wrote:
>> ---
>> ~this() {} // Finalizer
>> ~this() @nogc {} // Finalizer
>> ~this @deterministic {} // Destructor
>> ~this @nogc @deterministic {} // Destructor
>> }
>
> Yeah, this brings with it more flexibility. I'd prefer to avoid adding a new attribute for it, but this looks more interesting.
>
>
Some other options:
~~this() {}
!this() {}
!~this() {}
this!(true) () {} //not really a big fan of this version
|
July 26, 2017 Re: Destructors vs. Finalizers | ||||
---|---|---|---|---|
| ||||
Posted in reply to Mike Parker | On 7/26/17 8:57 AM, Mike Parker wrote: > On Wednesday, 26 July 2017 at 12:43:27 UTC, Steven Schveighoffer wrote: >> >> Regarding the OP, I think we really should strive to have something to fix this issue. >> >> A poor-mans distinction could be done by checking whether the GC is currently the one destroying (a flag is available, but isn't publicly accessible), though that could get expensive. > > That's essentially what Guillaume's "GC-proof resource class" idiom does now. > > https://p0nce.github.io/d-idioms/#GC-proof-resource-class > Yeah, I've seen that. https://issues.dlang.org/show_bug.cgi?id=17563 -Steve |
Copyright © 1999-2021 by the D Language Foundation