December 28, 2017
On Thursday, December 28, 2017 10:37:09 H. S. Teoh via Digitalmars-d-learn wrote:
> On Sun, Dec 24, 2017 at 02:07:26PM -0700, Jonathan M Davis via Digitalmars-d-learn wrote: [...]
>
> > Regardless, even if it were the case that it were guaranteed that all finalizers were run when the program exited, it would still be terrible practice to rely on it. It's trivial to end up in a situation where no collection is run for quite some time (e.g. just don't do much memory allocation for a while), which would leave any resources that needed to be freed by a finalizer unfreed for quite a while even though they weren't needed anymore. So practically speaking, it doesn't really matter where the finalizers are guaranteed to run. Relying on them to be run rather than forcing them to be run via destroy or using some other helper function is just going to cause problems, so it's just plain bad practice to rely on finalizers to be run to release resources. That's just life with GC's in general, not just D's. It's why C# has the while dispose/IDisposable thing, and why D code should either be using destroy to deal with freeing resources for a class or using structs on the stack for resources that need to be freed. Or alternate memory strategies can be used via std.experimental.allocator. The GC works great for lots of stuff but not for system resources. Honestly, in some ways, we'd be better off if D didn't even have finalizers.
>
> [...]
>
> This makes me wonder if a better approach to memory management is to use refcounting by default, and fallback to the GC to collect cycles.
>
> In my current project, I'll probably end up having to use RefCounted!Database just so I can have deterministic releasing of database handles without needing to worry about dangling references that may still be lingering around. (Currently, I'm just calling .destroy directly on the handle when I'm done with it, but there's a slim possibility that there might be dangling references left somewhere. So that needs to be addressed at some point.)

The GC works perfectly well for most things. You just have to be aware of its downsides - and that includes being aware of what's going to happen if you try and use it to manage system resources. For that, ref-counting is almost certainly going to be better (though there are probably cases where it doesn't matter, because it's not really a problem if the resources aren't freed before the program exits).

In any case, for a lot of the cases where dispose/IDisposable would be used in C#, ref-counting is almost certainly what the code should be doing (either that or scope statements if what's being done is localized and not common enough to create a type to use with RAII). That's probably on the list of things that needs to be written up somewhere as being among best practices for D. There are probably too many things like that that are sitting in the heads of a lot of folks but not necessarily well communicated to others - though this particular issue may have been discussed in the recent GC articles. I don't know. I still need to read them.

- Jonathan M Davis

January 31, 2018
On Thursday, 21 December 2017 at 18:20:19 UTC, H. S. Teoh wrote:
> I ended up calling .destroy on the class instance explicitly just so the destructor would run at the right time, right before nulling the reference so that the GC would collect the memory.

Pardon my probable ignorance (D newbie and all), but why wouldn't a 'delete' work for this?

https://dlang.org/spec/expression.html#delete_expressions
January 31, 2018
On Wednesday, 31 January 2018 at 10:14:53 UTC, DanielG wrote:

>
> Pardon my probable ignorance (D newbie and all), but why wouldn't a 'delete' work for this?
>
> https://dlang.org/spec/expression.html#delete_expressions

delete is deprecated:

https://dlang.org/deprecate.html#delete
January 31, 2018
On Wednesday, 31 January 2018 at 10:34:53 UTC, Mike Parker wrote:
> delete is deprecated:
>
> https://dlang.org/deprecate.html#delete

Ah, thanks! Actually double-thanks, because my progress through your book is what prompted me to search for threads about class destructors. The existence of .destroy answers my question (namely, "should I just use 'delete', or my own .dispose method, for deterministic resource freeing?")
January 31, 2018
On Thursday, 21 December 2017 at 18:45:27 UTC, Adam D. Ruppe wrote:
> On Thursday, 21 December 2017 at 18:20:19 UTC, H. S. Teoh wrote:
>> When the scoped destruction of structs isn't an option, RefCounted!T seems to be a less evil alternative than an unreliable class dtor. :-/
>
> Alas, RefCounted doesn't work well with inheritance...
>
> Though, what you could do is make the refcounted owners and borrow the actual reference later.

Is there some summary of the things you have to be aware of when using the GC in D and not using the GC? I feel this would be very useful especially for people that are new to D or are not used to that kind of issues (because coming from a GCed language).
January 31, 2018
On Wednesday, January 31, 2018 10:51:10 DanielG via Digitalmars-d-learn wrote:
> On Wednesday, 31 January 2018 at 10:34:53 UTC, Mike Parker wrote:
> > delete is deprecated:
> >
> > https://dlang.org/deprecate.html#delete
>
> Ah, thanks! Actually double-thanks, because my progress through your book is what prompted me to search for threads about class destructors. The existence of .destroy answers my question (namely, "should I just use 'delete', or my own .dispose method, for deterministic resource freeing?")

The main problem with delete is that it's inherently unsafe. GC-managed memory is supposed to be @safe (it's one of the main reasons that D has a GC in the first place), but having the programmer go and delete a GC-managed object rather than waiting for the GC to do it makes it trivial to do wrong stuff like free an object's memory while it's still referenced by something else (the sort of thing that the GC is supposed to avoid). It's far better to either explicitly destroy the object without freeing its memory or to use memory that is not managed by the GC if you want deterministic destruction of an object on the heap.

- Jonathan M Davis

February 01, 2018
On Wed, Jan 31, 2018 at 01:38:07PM +0000, Bienlein via Digitalmars-d-learn wrote:
> On Thursday, 21 December 2017 at 18:45:27 UTC, Adam D. Ruppe wrote:
> > On Thursday, 21 December 2017 at 18:20:19 UTC, H. S. Teoh wrote:
> > > When the scoped destruction of structs isn't an option, RefCounted!T seems to be a less evil alternative than an unreliable class dtor.  :-/
> > 
> > Alas, RefCounted doesn't work well with inheritance...
> > 
> > Though, what you could do is make the refcounted owners and borrow the actual reference later.
> 
> Is there some summary of the things you have to be aware of when using the GC in D and not using the GC? I feel this would be very useful especially for people that are new to D or are not used to that kind of issues (because coming from a GCed language).

D was originally designed with a GC in mind, so if you're using the GC and writing typical GC'd code, there's really not much to be aware of, esp. if you're coming from a GC'd language.  The only time you have to be actively concerned about the GC is if:

1) You're interacting with C code and passing pointers around. You may need to hold on to a copy of pointers you pass to C, because the GC does not know any pointer roots in C land, so it may wrongly collect something that the C code still holds a reference to.

2) You're writing performance-sensitive code and profiling shows that the GC is becoming a bottleneck.  The usual easy solution is to import core.memory and make use of GC.disable, GC.collect, GC.enable at strategic points in your code.

3) You need to do useful work in dtors, and/or need deterministic destruction, which is fundamentally incompatible with the GC.  In this case, probably your best bet is RefCounted or some other kind of non-GC memory management scheme.  Lately I'm beginning more and more to just avoid class dtors in general, due to their inherent unreliability, and just use scoped destruction (structs with dtors), or RefCounted, or some other memory management scheme (perhaps raw malloc/free if I need tight control over things).


T

-- 
VI = Visual Irritation
1 2 3
Next ›   Last »