July 26, 2017
On Wednesday, 26 July 2017 at 12:35:19 UTC, Mike Parker wrote:
> 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.

Note that Andrei once proposed in 2014 that the GC wouldn't call destructors/finalizers at all:

http://forum.dlang.org/post/ljrm0d$28vf$1@digitalmars.com
> We're considering deprecating ~this() for classes in the future.

Instead the forum community pushed back and what has been done is extending the calls to GC-allocated structs.
July 26, 2017
On Wednesday, 26 July 2017 at 13:54:15 UTC, Guillaume Piolat wrote:
> On Wednesday, 26 July 2017 at 12:35:19 UTC, Mike Parker wrote:
>> 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.
>
> Note that Andrei once proposed in 2014 that the GC wouldn't call destructors/finalizers at all:
>
> [...]

AFAICT that was mostly because it would have broken plenty of existing code.
Properly separating destruction and finalization from each other with the current syntax remaining as finalizers and the new one for destructors would allow this to be done without major code breakage.
July 26, 2017
@delete() {}
delete() {}

On Wed, Jul 26, 2017 at 3:08 PM, jmh530 via Digitalmars-d < digitalmars-d@puremagic.com> wrote:

> 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
On Wednesday, 26 July 2017 at 14:10:19 UTC, Moritz Maxeiner wrote:
> AFAICT that was mostly because it would have broken plenty of existing code.

The validity or purposefulness of such code is up to debate, a separate debate granted.
Let's assume there is working code that such a change will break.

> Properly separating destruction and finalization from each other with the current syntax remaining as finalizers and the new one for destructors would allow this to be done without major code breakage.

Sure, in the event D would like to transition towards a state where the GC doesn't call finalizers, it seems useful.

From a marketing point of view having two destructors and keyword/syntax just for this would be hard to defend, and it would also need to explain the whole story.

Personally I'd be for:

    ~this() { /* deterministic one */ }
    void finalize() { /* the one called by GC */ }

But then no transition path.

I'll defend the view point that there is _nothing_ useful to do in a finalizer except to check if the destructor has already been called.
July 26, 2017
On 7/26/17 10:57 AM, Guillaume Piolat wrote:

> I'll defend the view point that there is _nothing_ useful to do in a finalizer except to check if the destructor has already been called.

For instance, a destructor could destroy recursively all members at that time.

A finalizer would not be able to.

The thing to do in a finalizer that is useful is to release any non-GC resources.

-Steve
July 26, 2017
On Wednesday, 26 July 2017 at 14:57:14 UTC, Guillaume Piolat wrote:
>
> But then no transition path.
>

Does seem a bit like a nightmare...

It may facilitate a transition to add a destructor member function as well (C# has dispose as an interface, maybe that's better?). Then have a deprecation for ~this and tell people to use finalize or destructor, and then add back ~this with the property that the default ~this calls destructor if that's there.
July 26, 2017
On Wednesday, 26 July 2017 at 15:42:45 UTC, jmh530 wrote:
> On Wednesday, 26 July 2017 at 14:57:14 UTC, Guillaume Piolat wrote:
>>
>> But then no transition path.
>>
>
> Does seem a bit like a nightmare...
>
> It may facilitate a transition to add a destructor member function as well (C# has dispose as an interface, maybe that's better?). Then have a deprecation for ~this and tell people to use finalize or destructor, and then add back ~this with the property that the default ~this calls destructor if that's there.

Well I like this idea best.
To split C in A and B, deprecate C and tell what to do instead.

July 26, 2017
On Wednesday, 26 July 2017 at 15:15:03 UTC, Steven Schveighoffer wrote:
> On 7/26/17 10:57 AM, Guillaume Piolat wrote:
>
>> I'll defend the view point that there is _nothing_ useful to do in a finalizer except to check if the destructor has already been called.
>
> The thing to do in a finalizer that is useful is to release any non-GC resources.
>
> -Steve

Interesting case.

Do we assume the finalizer is always called after the destructor?

- If yes, then releasing these non-GC resources could have been possible in the destructor too. The only lost generality would be if releasing such non-GC resources would be faster from the GC thread (could well be since pooled).

- else, it's a case of the finalizer being calld by the GC and the destructor not being called. Is this considered a bug?
|
|   - If yes, then point of releasing resources is moot since we have a bug.
|
|   - If not, it means we want to allow not calling destructors.
|   |
|   |   => this implies we think finalizers will be called
|   |      I'll make claim this works for process-wide resources somehow (we stopped the last debate here), but not transient ones (eg: mutex) because of false pointers. The finalizer might be released late.

From these premises I conclude that the instructions given to new D programmers would be:

  1. you should destroy resources deterministically

  2. however GC objects owning resources may release them in their finalizer
    * except if you can't release them from any thread
    * except if these resources should be released before the GC shutdown (and then you have to explain why finalizer might not be called right now).



July 26, 2017
I don't get it. The GC collects the objects which aren't in use anymore. The order in which this is currently happening is not specified. So, how are the destructors supposed to be called in the right order? Manually? ARC? As far as I understand it, the GC can't do it, otherwise we wouldn't have the "random" order in which the finalizer are called in the first place.
July 26, 2017
On Wednesday, 26 July 2017 at 17:38:28 UTC, Dgame wrote:
> I don't get it. The GC collects the objects which aren't in use anymore. The order in which this is currently happening is not specified. So, how are the destructors supposed to be called in the right order? Manually? ARC?

After the split:
Destructors are only for deterministic end of object lifetime, so yes, they are to be called by any scheme (such as manual management via destroy and reference counting - which is likely also implemented as calling destroy) that is deterministic.
Finalizers are for nondeterministic schemes such as the GC.
The GC *never* calls destructors directly, only finalizers.
A finalizer might manually call a destructor, but a destructor may never call a finalizer.