@nogc, exceptions, generic containers... Issues.

Meta via Digitalmars-d digitalmars-d at puremagic.com
Mon Sep 8 22:13:41 PDT 2014


On Monday, 8 September 2014 at 15:55:53 UTC, monarch_dodra wrote:
> I'm starting this thread related to two issues I'm encountering 
> in regards to avoiding the GC, and the new @nogc attribute.
>
> 1) Issue 1)
> The first issue is in regards to Throwables. The issue here is 
> that they are allocated using the GC, so it is currently almost 
> impossible to throw an exception in a @nogc context. This is (I 
> think) a serious limitations. Do we have any plans, ideas, on 
> how to solve this?
>
> A particularly relevant example of this issue is `RefCounted`: 
> This struct uses malloc to ref count an object, give a 
> deterministic life cycle, and avoid the GC. Yet, since malloc 
> can fail, it does this:
> _store = cast(Impl*) enforce(malloc(Impl.sizeof));
> Can you see the issue? This object which specifically avoids 
> using the GC, end up NOT being @nogc.
>
> Any idea how to approach this problem?
>
> I know there are "workarounds", such as static pre-allocation, 
> but that also comes with its own set of problems.
>
> Maybe we could change it to say it's not legal to "hold on" to 
> exceptions for longer than they are being thrown? Then, we 
> could create the exceptions via allocators, which could 
> deterministically delete them at specific points in time (or by 
> the GC, if it is still running)? Just a crazy idea...
>
> 2) Issue 2)
> The second issue is that data which is placed in non-GC *may* 
> still need to be scanned, if it holds pointers. You can check 
> for this with hasIndirections!T. This is what RefCounted and 
> Array currently do. This is usually smart. There's a catch 
> though.
> If the object you are storing happens to hold pointers, but NOT 
> to GC data, they are still scanned.
>
> A tell-tale example of this problem is Array!int. You'd think 
> it's @nogc, right? The issue is that Array has a "Payload" 
> object, into which you place malloc'ed memory for your ints. 
> The Payload itself is placed in a RefCounted object. See where 
> this is going?
>
> Even though we *know* the Payload is malloc'ed, and references 
> malloc'ed data, it is still added to the GC's ranges of scanned 
> data. Even *if* we solved issue 1, then Array!int would still 
> *not* be @nogc, even though it absolutely does not use the GC.
>
> Just the same, an Array!(RefCounted!int) would also be scanned 
> by the GC, because RefCounted holds pointers...
>
> A *possible solution* to this problem would be to add an extra 
> parameter to these templates called "ScanGC", which would be 
> initialized to "hasIndirection!T". EG:
> struct Array(T, bool ScanGC = hasIndirections!T)
>
> Does this seem like a good idea? I don't really see any other 
> way around this if we want generic code with manual memory 
> management, that is "GC friendly" yet still useable in a @nogc 
> context.

It's not really a solution, but use of Nullable (or a theoretical 
option type) and a Result type in @nogc code can help remove the 
need for exceptions. An interesting data point is that Rust has a 
try! macro, which wraps an expression and translates into 
something like the following:

let ratio = try!(div(x, y));

becomes

let ratio = match div(x, y)
{
     Ok(val) => val,
     Err(msg) => { return Err; }
}

Maybe we need a similar solution for @nogc.


More information about the Digitalmars-d mailing list