GC vs Resource management.

monnoroch via Digitalmars-d digitalmars-d at puremagic.com
Sat May 3 05:28:02 PDT 2014


I've been reading all the topics with those "radical" ideas about 
the GC and dtors and, honestly, i'd rather call them "insane". 
After all the reading and thinking, i came to conclusion, that 
what Andrey suggests is to call dtors only on stack-allocated 
structs. That also implies, that one can't put those in 
containers and gc-allocated objects.
Since all of them: containers, structs, classes -- are all 
first-class objects they must be all nicely combined in code, 
without any unintuitive stuff.
I mean, really, let us look at c++ strings. There are const 
char*, std::sting, QString, Poco::String, icu::UnicodeString, and 
every big project uses it's own strings implementation that can't 
be used together in a sane way. That is what great in D: you just 
threw the idea of library-implemented strings away and made it 
not only "standard", but special and that what makes it intuitive 
and simple (unless you interact with c++). Never seen any 
non-standart strings for D.
The point is, that every library and every coder add to the 
project incompatible and difficult to use together stuff, so 
every programmer already has to think of all the problems with 
other's people code, and you just can't add same shit to the 
language. All elements must nicely interact together and 
otherwise it's a total disaster.
Back to the dtors: i understand, that all the stuff you propose 
could make GC faster, simpler, and cooler, but it sounds insane 
to anyone, who uses the language, not develops it, that if you 
create struct object, dror will be called, but if you place the 
copy in a container, it wont. It's just unanderstandable from 
user's point of view.

Now, for the solution.

First, we can just fix this shit with arrays of structs and 
that's it. That still lives us with false pointers problem: not 
everything gets collected. That's no good. So, i propose to think 
of actually separating gc-memory management (via GC) and other 
resources management: via some new (or maybe old) mechanism.

Let me start with listing of existing solutions:

1) C.
That is the simplest way: fully-manual resource management.
It's obvious, we can't do that in D, because it's supposed to be 
simpler for coding, than C.

2) Go.
Actually, this one is not that different: it uses GC for memory 
only, and manual management for all the rest (with help of defer 
operator). We can't do it either, for the same reasons.

3) C++.
This one is semi-automatic (talking about user code, not some 
allocator libraries): you choose the scheme (refcounting, unique 
reference) and then it'll do the rest.

4) Rust.
I'm not a pro here, but as i understand, it uses C++ way, and 
adds gc-collected pointers, but not sure, so help me here.

5) Python.
GC-only, except one clever case: with statement calls close() 
method.


Please, if there are any pros in other platforms, add your 
knowledge to this list, i would very much love to learn (same, if 
a made any mistakes).


Now, for D: obviously D has GC-managed heap. First, we should, 
like in Go, leave only managing gc-memory to the GC -- this is 
just rephrasing Andreys proposal.
The simplest way o manage all other resources would be manual, 
Go-way:

A a = A();
scope(exit)
     a.~A();

But it's to annoying, to that all the time, so we really want 
dtors to save us lost of typing and debugging, but they can't be 
called all the time, because we can put stuff in GC-collected 
objects.

What i propose, is to include new concept in D: scoped objects.
Any object (no matter is it a class or struct instance) can be 
either scoped or not.
Dtors for scoped objects are called when out of scope, dtors for 
non-scoped objects are not called at all.

It is actually as simple as rewrite code

A a = A();

as

A a = A();
scope(exit)
     a.~A();

For all a's, which are scoped objects.

For me, it is both a simple concept and good rationalization for 
difficult dror-gets-called-or-not rules.

That leaves only to determine, what objects are scoped. Well, 
that is obviously stack-allocated structs, gc-allocated scope 
classes and gc-allocated structs in scope classes.

But that is just my idea. This post has so many words, because 
it's very important, that D devs make good decision on that deep 
problem, and the key to such decision is information and 
discussion.

UPD:
Also, about arrays and slices: if we could easily pass them 
around as cost ref-s, just like in C++, then we could make them 
value-types and they wouldn't require any ref counting. I would 
suggest, make all "in" function arguments const refs.


More information about the Digitalmars-d mailing list