digitalmars.D - Error handling meeting summary
- Richard (Rikki) Andrew Cattermole (39/39) Jul 25 Hello all!
- monkyyy (6/46) Jul 25 While adding flags that increase safety, consider adding flags
- Steven Schveighoffer (5/10) Jul 25 Can you explain this? The link isn't very explanatory for those
- Richard (Rikki) Andrew Cattermole (33/48) Jul 26 Yeah sure.
- Sebastiaan Koppe (5/23) Jul 26 Unfortunately the explanation isn't very clear for me. Am I
- Richard (Rikki) Andrew Cattermole (4/30) Jul 26 Yes, that is correct.
- Adam D. Ruppe (40/43) Jul 26 OpenD implemented it back in May:
- Sebastiaan Koppe (3/10) Jul 27 Yes I saw you mention it in the mile-long thread on errors. Makes
Hello all! We've had a meeting on how error handling should work in D. Approved work: - Finalisers are brought back to the baseline behaviour. They will not be rewritten to sequences in the frontend. https://github.com/dlang/dmd/blob/3d06a911ac442e9cde5fd5340624339a23af6eb8/compiler/src/dmd/statementsem.d#L3428 - A CLI switch may be offered that performs rewriting of finally statements to sequences if an ``Exception`` is not thrown within the try body and finally statements will be rewritten to ``catch(Exception)`` statements. This is Walter's approach to error handling that he recommends. It cannot be made the default as it will break language features. - A filter method is added to the ``Thread`` class hierarchy; this filter method, by default, will call a grave digger global function pointer if set. Otherwise, all ``Throwable``'s will propagate like they do today. It was considered that perhaps it would be a good idea to a flag on ``Thread`` creation to determine if you want to kill the process if ``Error`` is seen. No decision is made but I see no reason a PR wouldn't be accepted if it only changes the default behaviour of the filter method. I'm happy to do finally statement being brought back to baseline, and filter method. However, it will be in the next two months, not now. If someone wants to get to it before me they may. Walter will have to do the CLI switch stuff, due to intersecting with dmd's glue code. Approved work for someone who wants to do it: - A pragma within a function that disables unwinding. Requires a DIP. Requires Iain&Martin's consultation. - Contracts being called in the caller, not callee. Walter wants a DIP document to cover the current state (does not need to go into the queue, it only has to exist). Timon offered to do it. Anyone can implement as long as we get the document. - Null deref read barrier aka null check. CLI switch, throw Error with a hook function. Noted that this is useful for platforms like web assembly and debugging CI's where no stack trace is present. Now for the trouble-making question, is there something that people need that I haven't covered in these lists?
Jul 25
On Friday, 25 July 2025 at 16:58:43 UTC, Richard (Rikki) Andrew Cattermole wrote:Hello all! We've had a meeting on how error handling should work in D. Approved work: - Finalisers are brought back to the baseline behaviour. They will not be rewritten to sequences in the frontend. https://github.com/dlang/dmd/blob/3d06a911ac442e9cde5fd5340624339a23af6eb8/compiler/src/dmd/statementsem.d#L3428 - A CLI switch may be offered that performs rewriting of finally statements to sequences if an ``Exception`` is not thrown within the try body and finally statements will be rewritten to ``catch(Exception)`` statements. This is Walter's approach to error handling that he recommends. It cannot be made the default as it will break language features. - A filter method is added to the ``Thread`` class hierarchy; this filter method, by default, will call a grave digger global function pointer if set. Otherwise, all ``Throwable``'s will propagate like they do today. It was considered that perhaps it would be a good idea to a flag on ``Thread`` creation to determine if you want to kill the process if ``Error`` is seen. No decision is made but I see no reason a PR wouldn't be accepted if it only changes the default behaviour of the filter method. I'm happy to do finally statement being brought back to baseline, and filter method. However, it will be in the next two months, not now. If someone wants to get to it before me they may. Walter will have to do the CLI switch stuff, due to intersecting with dmd's glue code. Approved work for someone who wants to do it: - A pragma within a function that disables unwinding. Requires a DIP. Requires Iain&Martin's consultation. - Contracts being called in the caller, not callee. Walter wants a DIP document to cover the current state (does not need to go into the queue, it only has to exist). Timon offered to do it. Anyone can implement as long as we get the document. - Null deref read barrier aka null check. CLI switch, throw Error with a hook function. Noted that this is useful for platforms like web assembly and debugging CI's where no stack trace is present. Now for the trouble-making question, is there something that people need that I haven't covered in these lists?While adding flags that increase safety, consider adding flags that decrease safety. Maybe replace int/0=>int.max or maybe exceptions are just replaced with `return` and maybe half of phoboes io functions work as is or any of my other hottakes
Jul 25
On Friday, 25 July 2025 at 16:58:43 UTC, Richard (Rikki) Andrew Cattermole wrote:Hello all! We've had a meeting on how error handling should work in D. Approved work: - Finalisers are brought back to the baseline behaviour. They will not be rewritten to sequences in the frontend.Can you explain this? The link isn't very explanatory for those who don't understand the DMD codebase. -Steve
Jul 25
On 26/07/2025 12:03 PM, Steven Schveighoffer wrote:On Friday, 25 July 2025 at 16:58:43 UTC, Richard (Rikki) Andrew Cattermole wrote:Yeah sure. Right now final statements are different behavior based upon if the trybody scope could throw an ``Exception`` class. If they do not throw an ``Exception``, it will rewrite it so that it is a sequence: ``trybody; finalbody;`` Final statements are used for a lot of things, running destructors of structs, or ``scope(exit)`` for instance. That's a problem, its half way between two cleanup strategies. Never run cleanup on throwing of an ``Error`` or always cleaning up when ``Error`` is thrown. An example of this behavior is the following code, where the destructor will run: ```d void do1() { assert(0); } void main() { static struct S { ~this() { import std.stdio; writeln("destructor ran!"); } } S s; do1; } ``` Bringing this back to baseline behavior of no rewrites, means that we can pick which strategy people want to use.Hello all! We've had a meeting on how error handling should work in D. Approved work: - Finalisers are brought back to the baseline behaviour. They will not be rewritten to sequences in the frontend.Can you explain this? The link isn't very explanatory for those who don't understand the DMD codebase. -Steve
Jul 26
On Saturday, 26 July 2025 at 19:55:17 UTC, Richard (Rikki) Andrew Cattermole wrote:On 26/07/2025 12:03 PM, Steven Schveighoffer wrote:Unfortunately the explanation isn't very clear for me. Am I correct to think that this will ensure structs in `nothrow` functions now get their destructors run on assert / throw Error?On Friday, 25 July 2025 at 16:58:43 UTC, Richard (Rikki) Andrew Cattermole wrote:Yeah sure. [...]Hello all! We've had a meeting on how error handling should work in D. Approved work: - Finalisers are brought back to the baseline behaviour. They will not be rewritten to sequences in the frontend.Can you explain this? The link isn't very explanatory for those who don't understand the DMD codebase. -Steve
Jul 26
On 27/07/2025 9:12 AM, Sebastiaan Koppe wrote:On Saturday, 26 July 2025 at 19:55:17 UTC, Richard (Rikki) Andrew Cattermole wrote:Yes, that is correct. Walter's approach where this does not happen will have a switch to enable (assuming he implements it).On 26/07/2025 12:03 PM, Steven Schveighoffer wrote:Unfortunately the explanation isn't very clear for me. Am I correct to think that this will ensure structs in `nothrow` functions now get their destructors run on assert / throw Error?On Friday, 25 July 2025 at 16:58:43 UTC, Richard (Rikki) Andrew Cattermole wrote:Yeah sure. [...]Hello all! We've had a meeting on how error handling should work in D. Approved work: - Finalisers are brought back to the baseline behaviour. They will not be rewritten to sequences in the frontend.Can you explain this? The link isn't very explanatory for those who don't understand the DMD codebase. -Steve
Jul 26
On Saturday, 26 July 2025 at 21:12:02 UTC, Sebastiaan Koppe wrote:Unfortunately the explanation isn't very clear for me. Am I correct to think that this will ensure structs in `nothrow` functions now get their destructors run on assert / throw Error?OpenD implemented it back in May: https://github.com/opendlang/opend/commit/40e11759a82175b2f5edfe855c53a75ce88f176c So you can always run a test case through the opend compiler to see what happens. Try this for example: ``` bool destroyed; struct A { ~this() { destroyed = true; } } void foo() nothrow { assert(0); } void thing() { A a; foo(); } void main() { try { thing(); } catch(Throwable t) { } assert(destroyed); } ``` You'd certainly expect `A`'s dtor to be called at the end of `thing`, but with upstream, that's not actually the case, since it thinks the function doesn't do anything that could throw (`foo` being marked `nothrow` is important to get this result), and thus never bothers setting up the `finally` block internally to call that dtor, it just tries to do it at normal function return. assert (and range error, or null pointer error - also implemented in opend a couple months ago, etc) ignore nothrow though, making it possible to break this assumption. Even if you never *caught* the `Throwable` like I did here, you still might notice the missing side effects of the destructor in other ways like if it did something outside your process.
Jul 26
On Sunday, 27 July 2025 at 01:05:57 UTC, Adam D. Ruppe wrote:On Saturday, 26 July 2025 at 21:12:02 UTC, Sebastiaan Koppe wrote:Yes I saw you mention it in the mile-long thread on errors. Makes a lot of sense. Might have to try out opend one day.Unfortunately the explanation isn't very clear for me. Am I correct to think that this will ensure structs in `nothrow` functions now get their destructors run on assert / throw Error?OpenD implemented it back in May:
Jul 27