Thread overview
@nogc and Exceptions
Sep 29, 2022
Quirin Schroll
Sep 29, 2022
Adam D Ruppe
Sep 29, 2022
IGotD-
Sep 29, 2022
Guillaume Piolat
Sep 29, 2022
Adam D Ruppe
Sep 30, 2022
rikki cattermole
Sep 30, 2022
Quirin Schroll
September 29, 2022

In the Q&A of Átila’s talk at DConf at 1:13:45, 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:

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.
September 29, 2022

On Thursday, 29 September 2022 at 12:12:34 UTC, Quirin Schroll wrote:

>
  • 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.

It actually already does this. Even if you malloc an exception (which you can), the exception's ctor will call the trace info hook, which GC allocates yet lies about it.

i've written a few random things about exceptions over the last year:
http://dpldocs.info/this-week-in-d/Blog.Posted_2021_08_16.html
http://dpldocs.info/this-week-in-d/Blog.Posted_2021_08_23.html
http://dpldocs.info/this-week-in-d/Blog.Posted_2022_06_27.html
http://dpldocs.info/this-week-in-d/Blog.Posted_2022_08_01.html#exception-template-concept

including some talk about just lying. nogc is kinda silly to begin with and if you want both nogc and nothrow you can... write nogc nothrow.

September 29, 2022

On Thursday, 29 September 2022 at 12:12:34 UTC, Quirin Schroll wrote:

>

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.

Deallocation is just as interesting for completeness in this example which was left out for some reason.

September 29, 2022

On Thursday, 29 September 2022 at 12:12:34 UTC, Quirin Schroll wrote:

>

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.

Why not allow to throw an immutable(char)[] value instead of Exception?
No destruction, allocation, and @nogc, and no DIP 1008 needed.
And it's usually enough for errors.
It would break chaining I guess.

Breaking the type system (@nogc) breaks D programs without runtime, or an impaired runtime. For sure one can rewrite it all with error codes, but well.

September 29, 2022

On Thursday, 29 September 2022 at 23:35:51 UTC, Guillaume Piolat wrote:

>

Why not allow to throw an immutable(char)[] value instead of Exception?

At that point, you might as well just throw an immutable static Error instance.

>

Breaking the type system (@nogc) breaks D programs without runtime, or an impaired runtime.

nogc and no druntime are entirely separate concepts. There's a little bit of overlap, but it is really easy to throw an exception allocated differently right now or otherwise depend on druntime while still satisfying nogc that it is maybe a useful filter reminder, but not at all comprehensive.

The most reliable way to see if something is no druntime compatible is to build it with no druntime and look for linker errors.

September 30, 2022
Something that I've been working on, although I'm not 100% there yet I think.

https://github.com/rikkimax/DIPs/blob/value_type_exceptions/DIPs/DIP1xxx-RC.md

September 30, 2022

On Friday, 30 September 2022 at 00:00:04 UTC, rikki cattermole wrote:

>

Something that I've been working on, although I'm not 100% there yet I think.

https://github.com/rikkimax/DIPs/blob/value_type_exceptions/DIPs/DIP1xxx-RC.md

I’ve skimmed your draft and it looks interesting. I’ll read it properly later today.