June 27, 2017
On 6/27/17 9:25 AM, Guillaume Piolat wrote:
> On Tuesday, 27 June 2017 at 13:11:10 UTC, Steven Schveighoffer wrote:
>> But I would use a close method, and not destroy(obj). The reason is because often times, you have wrapper types around your socket type, and just one extra level of indirection means the destructor cannot be used to clean up the socket (you are not allowed to access GC-allocated resources in a destructor).
> 
> All destructor restrictions do not apply when it's not called by the GC.
> 
> There really are two categories of destructors: called by the GC and called deterministically. Their usage should not overlap.

Yes, Tango solved this by having a separate "finalize()" method. I wish we had something like this.

> 
> My reasoning went with the following:
> 
> 1 - "I should have close() methods so that I don't rely on the GC, and the GC is calling ~this from the wrong thread etc, not everything can be released in this context (eg: OpenGL objects should be released from one thread only). Close methods will call close methods of "owned" objects."

I hadn't realized this, that is a good point. However, not all resources are restricted this much.

> That's how the GC-proof resource class came to existence, after many destruction bugs, and it let's you use the GC as a detector for non-deterministic destruction. I miss it in @nogc :)
> 
> https://p0nce.github.io/d-idioms/#GC-proof-resource-class

There are definitely better ways to do this than trying to allocate and catching an error. The GC knows the GC is running, use that mechanism instead :)

> Remember years ago when Alexandrescu suggested the GC shouldn't call heap destructors? That's what we get for having said no at the time.

No, the issue is that there isn't a separate call for destruction and GC. I think we should add this.

The GC still needs to call something to clean up non-memory resources, but having a call to use when cleaning up deterministically can make resource management more efficient (even memory resource management).

-Steve

-Steve
June 27, 2017
On 6/27/17 11:24 AM, Steven Schveighoffer wrote:
> On 6/27/17 9:25 AM, Guillaume Piolat wrote:

>> That's how the GC-proof resource class came to existence, after many destruction bugs, and it let's you use the GC as a detector for non-deterministic destruction. I miss it in @nogc :)
>>
>> https://p0nce.github.io/d-idioms/#GC-proof-resource-class
> 
> There are definitely better ways to do this than trying to allocate and catching an error. The GC knows the GC is running, use that mechanism instead :)

https://github.com/dlang/druntime/blob/master/src/gc/gcinterface.d#L189
https://github.com/dlang/druntime/blob/master/src/core/memory.d#L150

Apparently that info is limited to the core.memory package. But it's extern(C), so declaring the prototype should work. Should be much more efficient than allocating a byte (which I see you don't delete if it works), and catching an error.

-Steve
June 27, 2017
On 6/27/17 12:16 PM, Steven Schveighoffer wrote:
> On 6/27/17 11:24 AM, Steven Schveighoffer wrote:
>> On 6/27/17 9:25 AM, Guillaume Piolat wrote:
> 
>>> That's how the GC-proof resource class came to existence, after many destruction bugs, and it let's you use the GC as a detector for non-deterministic destruction. I miss it in @nogc :)
>>>
>>> https://p0nce.github.io/d-idioms/#GC-proof-resource-class
>>
>> There are definitely better ways to do this than trying to allocate and catching an error. The GC knows the GC is running, use that mechanism instead :)
> 
> https://github.com/dlang/druntime/blob/master/src/gc/gcinterface.d#L189
> https://github.com/dlang/druntime/blob/master/src/core/memory.d#L150
> 
> Apparently that info is limited to the core.memory package. But it's extern(C), so declaring the prototype should work. Should be much more efficient than allocating a byte (which I see you don't delete if it works), and catching an error.

Just added this enhancement to publicize this function: https://issues.dlang.org/show_bug.cgi?id=17563

-Steve
June 27, 2017
On Tuesday, 27 June 2017 at 15:24:00 UTC, Steven Schveighoffer wrote:
> On 6/27/17 9:25 AM, Guillaume Piolat wrote:
>> On Tuesday, 27 June 2017 at 13:11:10 UTC, Steven Schveighoffer wrote:
>>> But I would use a close method, and not destroy(obj). The reason is because often times, you have wrapper types around your socket type, and just one extra level of indirection means the destructor cannot be used to clean up the socket (you are not allowed to access GC-allocated resources in a destructor).
>> 
>> All destructor restrictions do not apply when it's not called by the GC.
>> 
>> There really are two categories of destructors: called by the GC and called deterministically. Their usage should not overlap.
>
> Yes, Tango solved this by having a separate "finalize()" method. I wish we had something like this.

Well, technically speaking the `~this` for D classes *is* a finalizer that you may optionally manually call (e.g. via destroy).
It would be nice, though, to change class `~this` into a destructor and move the finalization into an extra method like `finalize`. Write a DIP?
June 27, 2017
On 6/27/17 2:04 PM, Moritz Maxeiner wrote:
> On Tuesday, 27 June 2017 at 15:24:00 UTC, Steven Schveighoffer wrote:
>> On 6/27/17 9:25 AM, Guillaume Piolat wrote:
>>> On Tuesday, 27 June 2017 at 13:11:10 UTC, Steven Schveighoffer wrote:
>>>> But I would use a close method, and not destroy(obj). The reason is because often times, you have wrapper types around your socket type, and just one extra level of indirection means the destructor cannot be used to clean up the socket (you are not allowed to access GC-allocated resources in a destructor).
>>>
>>> All destructor restrictions do not apply when it's not called by the GC.
>>>
>>> There really are two categories of destructors: called by the GC and called deterministically. Their usage should not overlap.
>>
>> Yes, Tango solved this by having a separate "finalize()" method. I wish we had something like this.
> 
> Well, technically speaking the `~this` for D classes *is* a finalizer that you may optionally manually call (e.g. via destroy).
> It would be nice, though, to change class `~this` into a destructor and move the finalization into an extra method like `finalize`. Write a DIP?

I don't have enough motivation to do this. But if we do anything, we should look at what Tango has done. It may not work exactly for druntime because of existing code, but it obviously didn't need compiler changes to work.

-Steve
June 27, 2017
On Tuesday, 27 June 2017 at 10:14:16 UTC, Jonathan M Davis wrote:
> On Tuesday, June 27, 2017 09:54:19 John Burton via Digitalmars-d-learn wrote:
>> [...]
>
> Arguably, std.socket should have used structs instead of classes for sockets for precisely this reason (though there are some advantages in using inheritance with sockets). But yes, calling close manually is the correct thing to do. Relying on the GC to call a destructor/finalizer is error-prone. There is no guarantee that the memory will ever be freed (e.g. the runtime could choose to not bother doing cleanup on shutdown), and even if the GC does collect it, there are no guarantees about how soon it will do so. However, if you keep allocating memory with the GC, then over time, the GC will collect GC-allocated memory that isn't currently being used so that it can reuse the memory. So, you really don't need to worry about the memory unless it becomes a bottleneck. It will be collected and reused, not leaked.
>
> [...]

I agree with that it should have been structs. The inheritance issue could be fixed by having a private member of the struct in a class, that way there could still be a class wrapper around it.
June 27, 2017
On Tuesday, 27 June 2017 at 15:24:00 UTC, Steven Schveighoffer wrote:
> The GC still needs to call something to clean up non-memory resources,

Well, I'd much prefer if the GC would simply not call destructors. Yes, destructor can work for _some_ resources, but because of ordering it also create accidental correctness, or just doesn't work with other resources.

> but having a call to use when cleaning up deterministically can make resource management more efficient (even memory resource management).

Yes. My point is that the destructor is uniquely positionned to be that call.
(This would also enables back failing destructors through the use of exceptions.)

In current D the problem with allowing the GC to close resources is that there is no ordering of destructors. A sub-tree of the ownership graph is freed by the GC together, but sometime an order is required for releasing.

Typically: you want to release a SDL_Texture but the Derelict SharedLib object has been freed already, so you can't call sdl_releaseTexture. It doesn't matter that the texture object held a reference to the ShareLib object since the sub-tree is destroyed together. close() methods don't help with that, the problem is with the GC calling destructors.


And if _some_ resource needs an ordering, then this property leak on their owners, so little by little the whole ownership graph need determinism.
June 27, 2017
On Tuesday, 27 June 2017 at 18:04:36 UTC, Moritz Maxeiner wrote:
>
> Well, technically speaking the `~this` for D classes *is* a finalizer that you may optionally manually call (e.g. via destroy).
> It would be nice, though, to change class `~this` into a destructor and move the finalization into an extra method like `finalize`. Write a DIP?

The only sane way out is to prevent the GC from calling constructors.
June 27, 2017
On Tuesday, 27 June 2017 at 23:42:38 UTC, Guillaume Piolat wrote:
> On Tuesday, 27 June 2017 at 18:04:36 UTC, Moritz Maxeiner wrote:
>>
>> Well, technically speaking the `~this` for D classes *is* a finalizer that you may optionally manually call (e.g. via destroy).
>> It would be nice, though, to change class `~this` into a destructor and move the finalization into an extra method like `finalize`. Write a DIP?
>
> The only sane way out is to prevent the GC from calling constructors.

Do you mean destructors?
If so, that's what I meant with the "technically". If the may GC call it (automatically), it's a finalizer, not a destructor (in the usual sense, anyway).
- Replace calls by the GC to `~this` with calls to `finalize` (or invent some cool other shortened name for the latter)
- Reserve `~this` for being called by deterministic lifetime management (std.experimental.allocator.dispose, object.destroy, RefCounted, Unique, etc.)

June 28, 2017
On Tuesday, 27 June 2017 at 23:54:50 UTC, Moritz Maxeiner wrote:
>
> Do you mean destructors?

Yes.


> - Replace calls by the GC to `~this` with calls to `finalize` (or invent some cool other shortened name for the latter)

My point is that in such a "finalize()" function the only sane things to do is to crash if the resource wasn't freed already. Why so?

See my texture example in: https://forum.dlang.org/post/kliasvljzwjhzuzibuae@forum.dlang.org

More simply:
If A needs an alive B to be destroyed, then neither A-owns-B or B-owns-A can guarantee the ordering under GC destruction.

Furthermore, this is viral. Whoever owns A needs an alive B to be destroyed.



> - Reserve `~this` for being called by deterministic lifetime management (std.experimental.allocator.dispose, object.destroy, RefCounted, Unique, etc.)

That's precisely what the GC-proof-resource-class allows, by preventing defective, non-composable usages of ~this.