On Thursday, 6 September 2018 at 14:39:12 UTC, Andrei
Alexandrescu wrote:
First off, there's no tree of exceptions simply because... well
it's not there. There is on field "next", not two fields "left"
and "right". It's a linear list, not a tree. During
construction there might be the situation whereby two lists
need to be merged. But they will be merged by necessity into a
singly-linked list, not a tree, because we have no structural
representation of a tree.
The runtime appends any exception raised by a `scope
(exit|failure)` statement to the next list of an exception
already being raised. So if I write:
scope (exit) throw new Exception("scope 1");
scope (exit) throw new Exception("scope 2");
throw new Exception("primary");
I get output like:
object.Exception@scratch.d(21): primary
----------------
??:? void scratch.throwy() [0x53a74c01]
??:? _Dmain [0x53a74d68]
object.Exception@scratch.d(26): scope 2
----------------
??:? void scratch.throwy() [0x53a74ce1]
??:? _Dmain [0x53a74d68]
object.Exception@scratch.d(25): scope 1
----------------
??:? void scratch.throwy() [0x53a74d42]
??:? _Dmain [0x53a74d68]
Okay, that seems reasonable. But what if each of those
`scope(exit)` statements had their own chains?
scope (exit) throw new Exception("scope 1", new Exception("cause
1"));
scope (exit) throw new Exception("scope 2", new Exception("cause
2"));
throw new Exception("primary");
object.Exception@scratch.d(8): primary
----------------
??:? void scratch.throwy() [0x7259caf3]
??:? _Dmain [0x7259cc64]
object.Exception@scratch.d(7): scope 2
----------------
??:? void scratch.throwy() [0x7259cba5]
??:? _Dmain [0x7259cc64]
object.Exception@scratch.d(7): cause 2
object.Exception@scratch.d(6): scope 1
----------------
??:? void scratch.throwy() [0x7259cc4c]
??:? _Dmain [0x7259cc64]
object.Exception@scratch.d(6): cause 1
The actual structure of the exceptions: `primary` has children
`scope 2` and `scope 1`; `scope 2` has child `cause 2`; `scope 1`
has child `cause 1`. A tree.
The encoded structure: a linked list where only the first two
positions have any structure-related meaning and the rest are
just a sort of mish-mash.
This isn't a situation you get in Java because Java doesn't have
a way to enqueue multiple independent actions at the end of the
same block. You just have try/finally and try(closeable).
(As an aside, it does seem we could allow some weird cases
where people rethrow some exception down the chain, thus
creating loops. Hopefully that's handled properly.)
Not if you semi-manually create the loop:
auto e = new Exception("root");
scope (exit) throw new Exception("scope 1", e);
throw e;
Filed as https://issues.dlang.org/show_bug.cgi?id=19231