RFC: moving forward with @nogc Phobos

Shammah Chancellor via Digitalmars-d digitalmars-d at puremagic.com
Mon Sep 29 11:44:11 PDT 2014


On 2014-09-29 10:49:52 +0000, Andrei Alexandrescu said:

> Back when I've first introduced RCString I hinted that we have a larger 
> strategy in mind. Here it is.
> 
> The basic tenet of the approach is to reckon and act on the fact that 
> memory allocation (the subject of allocators) is an entirely distinct 
> topic from memory management, and more generally resource management. 
> This clarifies that it would be wrong to approach alternatives to GC in 
> Phobos by means of allocators. GC is not only an approach to memory 
> allocation, but also an approach to memory management. Reducing it to 
> either one is a mistake. In hindsight this looks rather obvious but it 
> has caused me and many people better than myself a lot of headache.
> 
> That said allocators are nice to have and use, and I will definitely 
> follow up with std.allocator. However, std.allocator is not the key to 
> a @nogc Phobos.
> 
> Nor are ranges. There is an attitude that either output ranges, or 
> input ranges in conjunction with lazy computation, would solve the 
> issue of creating garbage. 
> https://github.com/D-Programming-Language/phobos/pull/2423 is a good 
> illustration of the latter approach: a range would be lazily created by 
> chaining stuff together. A range-based approach would take us further 
> than the allocators, but I see the following issues with it:
> 
> (a) the whole approach doesn't stand scrutiny for non-linear outputs, 
> e.g. outputting some sort of associative array or really any composite 
> type quickly becomes tenuous either with an output range (eager) or 
> with exposing an input range (lazy);
> 
> (b) makes the style of programming without GC radically different, and 
> much more cumbersome, than programming with GC; as a consequence, 
> programmers who consider changing one approach to another, or 
> implementing an algorithm neutral to it, are looking at a major rewrite;
> 
> (c) would make D/@nogc a poor cousin of C++. This is quite out of 
> character; technically, I have long gotten used to seeing most 
> elaborate C++ code like poor emulation of simple D idioms. But C++ has 
> spent years and decades taking to perfection an approach without a 
> tracing garbage collector. A departure from that would need to be 
> superior, and that doesn't seem to be the case with range-based 
> approaches.
> 
> ===========
> 
> Now that we clarified that these existing attempts are not going to 
> work well, the question remains what does. For Phobos I'm thinking of 
> defining and using three policies:
> 
> enum MemoryManagementPolicy { gc, rc, mrc }
> immutable
>      gc = ResourceManagementPolicy.gc,
>      rc = ResourceManagementPolicy.rc,
>      mrc = ResourceManagementPolicy.mrc;
> 
> The three policies are:
> 
> (a) gc is the classic garbage-collected style of management;
> 
> (b) rc is a reference-counted style still backed by the GC, i.e. the GC 
> will still be able to pick up cycles and other kinds of leaks.
> 
> (c) mrc is a reference-counted style backed by malloc.
> 
> (It should be possible to collapse rc and mrc together and make the 
> distinction dynamically, at runtime. I'm distinguishing them statically 
> here for expository purposes.)
> 
> The policy is a template parameter to functions in Phobos (and 
> elsewhere), and informs the functions e.g. what types to return. 
> Consider:
> 
> auto setExtension(MemoryManagementPolicy mmp = gc, R1, R2)(R1 path, R2 ext)
> if (...)
> {
>      static if (mmp == gc) alias S = string;
>      else alias S = RCString;
>      S result;
>      ...
>      return result;
> }
> 
> On the caller side:
> 
> auto p1 = setExtension("hello", ".txt"); // fine, use gc
> auto p2 = setExtension!gc("hello", ".txt"); // same
> auto p3 = setExtension!rc("hello", ".txt"); // fine, use rc
> 
> So by default it's going to continue being business as usual, but 
> certain functions will allow passing in a (defaulted) policy for memory 
> management.
> 
> Destroy!
> 
> 
> Andrei

I don't like the idea of having to pass in template parameters 
everywhere -- even for allocators.  Is there some way we could have 
"allocator contexts"?

E.G.

with( auto allocator = ReferencedCounted() )
{
	auto foo = setExtension("hello", "txt");
}

ReferenceCounted() could replace a thread-local "new" delegate with 
something it has, and when it goes out of scope, it would reset it to 
whatever it was before.   This would create some runtime overhead -- 
but I'm not sure how much more than already exists.

-Shammah



More information about the Digitalmars-d mailing list