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