The D standard library is built on GC, is that a negative or positive?
cc
cc at nevernet.com
Wed Dec 14 08:01:47 UTC 2022
On Tuesday, 13 December 2022 at 07:11:34 UTC, thebluepandabear
wrote:
> Does this claim have merit? I am not far enough into learning
> D, so I haven't touched GC stuff yet, but I am curious what the
> D community has to say about this issue.
I disagree with the majority opinion on this subject. I find D's
GC to often be heavily oversold, when it is particularly not
applicable to many portions of my use case (game development).
It certainly solves certain problems, but it introduces new ones.
The emphasis behind the GC mentality seems to be that most(all!)
people will never encounter those for their purposes and so they
should literally just not think about it and trust the GC, until
you suddenly can't anymore and the whole thing breaks apart.
Alternative strategies do exist obviously, but they're often
shoved into the backroom, with the salespeople only leading the
customers to them after much grumbling and fumbling with their
keys.
How do you instantiate a class object in D using the GC?
```d
new Foo;
```
How do you instantiate one using malloc? Something like:
```d
import core.memory;
import core.stdc.stdlib : malloc, free;
import core.lifetime : emplace;
T NEW(T, Args...)(auto ref Args args) /*@nogc (nope!)*/ if (is(T
== class)) {
enum size = __traits(classInstanceSize, T);
void* mem = malloc(size);
scope(failure) free(mem);
//throw OOMError.get("Out of Memory in NEW!"~T.stringof); //
wanna GC-allocate here? use a predefined object? or just ignore?
return mem !is null ? emplace!T(mem[0..size], args) : null;
}
// and don't forget
void FREE(T)(ref T obj) /*@nogc*/ if (is(T == class)) {
if (obj is null) return;
auto mem = cast(void*) obj;
//debug if (!GC.inFinalizer && GC.addrOf(mem)) return;
scope(exit) free(mem);
destroy(obj);
obj = null;
}
```
To people who are experienced with D, that's par for the course.
And people who have already done a good deal of thinking about
memory management in performance-intensive scenarios will
understand the need to know their language's alternatives to
begin with. But showing that to people coming to D as the
alternative to what you're supposed to think is the *right* way
everyone should use is just not attractive. It's a contradiction
in one of D's core philosophies, IMO: "Solve basic problems and
prevent easy bugs that most people walk into without thinking",
which sounds like an admirable goal aimed at drawing in and
protecting new users. Except then they're given a tool that will
just create problems if used in the intended way (not thinking
about it) if they get into certain domains of development. The
explanation of "Well, obviously you need to think about it if
you're going to be doing THAT!" just doesn't mesh with the way
it's initially sold.
Pipe dream: Why not `new malloc Foo;`? (or "deterministic" or
something. and then, `new rc Foo;`!) What if, to prevent
accidental intermingling, it were a storage class? `malloc Foo
mfoo = new Foo; // Error!`. Just thinking out loud. Part of
this can already be done by wrapping everything in structs and
templates. But just more noise!
That said, regarding your specific question, there are numerous
parts of the D standard library you can safely use without
allocating with the GC (and I do, and still love it) and
non-allocating alternatives are often added (e.g. `.join` vs
`.joiner`). Though the problem exists many components can't be
*explicitly* `@nogc` (a caveat I find it just not worth it to
worry about anymore- it takes up too much time and effort that
could be better spent on the code itself than on solving a
trillion compiler errors trying to satisfy every possible aspect
and edge case of @nogc-dom).
There is a lot of code you can write in D that, without going
over the stdlib with a fine-toothed comb, you can be reasonably
sure *will probably never* GC-allocate, even if it's not
explicitly @nogc, if that's an acceptable tradeoff for the code
safety requirements in your use case. std.container.array is
good, as previously mentioned. You can build on this and make
malloc/ref-counted variations of hashmaps/associative arrays too
(if you want to spend the effort on it). I believe there are
some third-party libraries up on dub for that already. The
operator overloading and syntactic sugar is good enough that
everything can look "just like" native D runtime/GC constructs if
you want, except for some declarations (but all that is not
exactly "out of the box", if we're still thinking of the
prospective new user context here).
tl;dr: I don't *hate* the GC. It's great for one&dones. I just
wish it wasn't so heavily lauded as The Truth & The Way.
More information about the Digitalmars-d
mailing list