RFC: Change what assert does on error
Dennis
dkorpel at gmail.com
Tue Jul 8 14:05:25 UTC 2025
On Sunday, 6 July 2025 at 23:53:54 UTC, Timon Gehr wrote:
> `nothrow` does not actually have this meaning, otherwise it
> would need to be `@system`
I'd say nothrow de-facto has this meaning (per Walter's
intention), and catching Error is currently `@system`, although
only implied by documentation and not enforced by the compiler.
> Here's the output with opend-dmd:
So I take it opend changed that, being okay with the breaking
change? Because @safe constructors of structs containing fields
with @system destructors will now raise a safety error even with
`nothrow`.
> This is great stuff! But it's not enabled by default, so there
> will usually be at least one painful crash. :(
Indeed, I tried enabling it by default in my original PR but it
broke certain Fiber tests, and there were some (legitemate)
doubts about multi-threaded programs and interfering with
debuggers so that's still todo.
> Well, you were asking for practical experience.
Specifically related to stack unwinding. The logic "throw Error()
should consistently run all cleanup code because a null
dereference just segfaults and that sucks" escapes me, but:
> Taking error
> reporting that just works and turning it into a segfault
> outright or even just requiring some additional hoops to be
> jumped through that were not previously necessary to get the
> info is just not what I need or want, it's most similar to the
> current default segfault experience.
That tracks. I guess the confusion came from two discussions
happening at once: doubling down on `throw Error()` and doubling
down on `abort()` on error.
> I don't really need it, but compiler-checked documentation that
> a function has no intended exceptional control ...
Some people in this thread argue that code should be Exception
safe even in the case of an index out of bounds error. If that's
the case, the `throw` / `nothrow` distinction seems completely
redundant. Imagine the author of a library you use writes this:
```D
mutex.lock();
arr[i]++;
mutex.unlock();
```
Instead of this:
```D
mutex.lock();
scope(exit) mutex.unlock();
arr[i]++;
```
The idea that best-case Errors (caught right before UB) function
just like Exceptions breaks down. `nothrow` is useless if you
don't want anyone to write different code based on its
presence/absence, right?
> In any case, doing this implicitly anywhere is the purest form
> of premature optimization.
While I can't say I have the numbers to prove that its
performance is important to me, I currently like the idea that
scope(exit)/destructors are a zero-cost abstraction when
Exceptions are absent. Having in the back in the mind that it
would be more efficient to manually write free() at the end of my
function instead of using safe scoped destruction might just
(irrationally) haunt me 😜.
> Correctness trumps minor performance improvements.
I'd usually agree wholeheartedly, but in this situation it's
"correctness after something incorrect has already happened" vs.
"performance of the correct case" which is more nuanced.
More information about the Digitalmars-d
mailing list