www.digitalmars.com         C & C++   DMDScript  

digitalmars.D - nogc and Exceptions

reply Quirin Schroll <qs.il.paperinik gmail.com> writes:
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.
Sep 29 2022
next sibling parent Adam D Ruppe <destructionator gmail.com> writes:
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.
Sep 29 2022
prev sibling next sibling parent IGotD- <nise nise.com> writes:
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.
Sep 29 2022
prev sibling parent reply Guillaume Piolat <spam spam.org> writes:
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.
Sep 29 2022
next sibling parent Adam D Ruppe <destructionator gmail.com> writes:
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.
Sep 29 2022
prev sibling parent reply rikki cattermole <rikki cattermole.co.nz> writes:
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
Sep 29 2022
parent Quirin Schroll <qs.il.paperinik gmail.com> writes:
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.
Sep 30 2022