DIP 1008 Preliminary Review Round 1

Stanislav Blinov via Digitalmars-d digitalmars-d at puremagic.com
Fri May 19 12:53:36 PDT 2017


On Friday, 19 May 2017 at 18:16:33 UTC, Jack Stouffer wrote:
> On Friday, 19 May 2017 at 15:45:28 UTC, Mike Parker wrote:
>> ...

> Secondly, I'm not a fan of special casing syntax, especially 
> when I don't think the given benefits outweigh the above listed 
> costs...

You're raising an extremely important point. Special-casing 
exceptions in such a way, while may help *some* code, is still a 
crutch, and a very ugly one at that. The bigger issue of @nogc is 
the implicit allocations. It would be much better to solve the 
fundamental problem, that is, give user code optional, but 
complete control over memory allocation.

All three main areas need to be addressed in concert: classes, 
arrays and delegates. Working on just one area, and even just a 
subset of it (exceptions) in the long run will further the 
problem, not help solve it.

As an example, operator new could accept additional syntax (outer 
[] mean "optional"):

new [(TAllocator)] Type [[count]] [(init)]

Where TAllocator is a class providing at least minimal allocator 
interface (allocate/deallocate). @nogc can be inferred from the 
allocator.
This lets user code decide on their class and array allocations. 
OTOH, this will incur storage penalty, since all 
dynamically-allocated objects (including arrays) will have to 
carry the allocator reference with them. It doesn't, however, 
solve the @nogc inference in general, since allocator is not part 
of the type. Attempting to concatenate two arrays at a distance 
from their allocation site would not be considered @nogc. That 
being said, arrays with complete inference support could be made 
library types, so perhaps that is not *that* big of an issue.

Delegates, as they are now, require a lot more attention. 
Firstly, there is the dubious design decision that any outer 
scope access is always by reference, which imposes the GC 
allocation of closures in the first place. @nogc cannot be solved 
for delegates without addressing control over captures. Then we 
have the allocation itself, in cases when it is desired. And that 
will completely destroy existing delegate syntax.

There is, however, another side to this problem, and that is 
interaction of exceptions with the runtime. Allowing users to 
employ any desired allocation scheme precludes reliable exception 
handling, since the runtime effectively loses control over 
exception lifetime. Catching garbage in a catch(...) block would 
never be a pleasant surprise. That being said, it's not that it 
is in control right now either:

void innocent() {
     throw new Exception("I am innocent");
}

void malicious() {
     try {
         innocent();
     } catch (Exception e) {
         // innocent, eh? well I am not...
         e.destroy;
         throw e;
     }
}

void oblivious() {
     try {
         malicious();
     } catch (Exception e) {
         writeln("Caught: ", e.msg);
     }
}

void main() {
     oblivious();
}

Hello, segmentation fault. If users want to be difficult, they'd 
find a way :)

So perhaps, instead of tackling exceptions on their own, we 
really should focus on allocation in general. Everything else 
should (hopefully) come automagically.


More information about the Digitalmars-d mailing list