@nogc and Exceptions
Quirin Schroll
qs.il.paperinik at gmail.com
Thu Sep 29 12:12:34 UTC 2022
In the [Q&A of Átila’s talk at DConf at
1:13:45](https://youtu.be/ksNGwLTe0Ps?t=4425), someone asks if
allocating and throwing exceptions might be a the case where you
wouldn’t mind the GC even in supposed `@nogc` code: When an
`Error` is thrown, the application is doomed anyways; when an
`Exception` is thrown, you already subscribed to inefficient
execution.
There’s a few options:
* Ignore the issue at a language level and just lie (code below):
Make an `Exception` allocating function and cast it to `@nogc`. I
do not know if that is UB.
* Make `@nogc` not apply to a `Throwable` allocated in a `throw`
expression.
* Introduce Yet Another Damn Function Attribute (YADMA)
`@nogcUnlessThrown`.
The code to lie:
```d
template throw_new(E : Throwable, Args...)
{
alias doAllocate = function E(Args args) => new E(args);
noreturn throw_new(Args args) @nogc
{
import std.algorithm.comparison : among;
enum isSafe =
"@safe".among(__traits(getFunctionAttributes, doAllocate)) > 0;
enum isPure =
"pure".among(__traits(getFunctionAttributes, doAllocate)) > 0;
alias FP = mixin("E function(Args) @nogc ",
isSafe ? "@safe " : "", isPure ? "pure" : "");
immutable hackedAllocate = (() @trusted =>
cast(FP)(doAllocate))();
throw hackedAllocate(args);
}
}
void test() @nogc @safe pure
{
import std.format : FormatException;
throw_new!FormatException("msg");
}
void main() @safe
{
import std.format : FormatException;
try
{
test();
}
catch (FormatException e)
{
import std.stdio;
writeln(e.msg);
}
}
```
Some explanation for why it is like this:
* One has to use `alias doAllocate = function E(Args args) => new
E(args);` instead of a normal function definition because a
normal function definition does not infer attributes.
`throw_new` has attributes inferred.
* `isSafe` and `isPure` take care that those attributes are
carried through if `E`’s constructor happens to have them.
* `hackedAllocate` is created via a `@trusted` block because
adding `@nogc` is not `@safe`. It only trusts the cast, not the
call.
* Perfect forwarding for the arguments is not trivial (I tried),
but probably not needed anyway.
More information about the Digitalmars-d
mailing list