(Note: Looks like there is a bug regarding Error.bypassedException
member. Would others please confirm.)
On 12/12/2016 01:15 PM, Yuxuan Shui wrote:
> I read https://dlang.org/spec/statement.html, which told me that Error
> is different in the way it's chained. But that is pretty vague, and I'm
> still confused.
>
> Can someone explain that using examples?
>
> Thanks.
You're referring to "[Errors] bypass the normal chaining mechanism, such
that the chain can only be caught by catching the first Error." What it
means is that an Error cannot be a collateral of an Exception, hiding in
its chain. So, when there is an Error that would otherwise be a
collateral of an Exception, you cannot catch the original Exception.
What is more importantly in-flight at that time is the Error.
The following program causes a chain of exceptions:
import std.stdio;
import std.string;
import std.range;
class TestException : Exception {
this(string msg) {
const fullMmsg = format("%s: %s",typeof(this).stringof, msg);
writefln("throwing '%s'", fullMmsg);
super(fullMmsg);
}
}
class TestError : Error {
this(string msg) {
const fullMmsg = format("%s: %s",typeof(this).stringof, msg);
writefln("throwing '%s'", fullMmsg);
super(fullMmsg);
}
}
// Causes an exception chain where the node at index errorIndex is an
// Error (others are all Exceptions).
void causeExceptionChain(size_t chainLength, size_t errorIndex) {
void throws(size_t n) {
scope (exit) {
const msg = format("%s", n);
if (n == errorIndex) {
throw new TestError(msg);
}
else {
throw new TestException(msg);
}
}
if (n != 0) {
// Redundant 'return' keyword due to
// https://issues.dlang.org/show_bug.cgi?id=16960
return throws(n - 1);
}
}
throws(chainLength - 1);
}
void main() {
try {
// -1 would mean "no Error in the chain". Change this to a
// number between 0 and 4 (inclusive) then you will realize
// that the Exception below will not be caught.
size_t errorIndex = -1;
causeExceptionChain(5, errorIndex);
}
catch (Exception original) {
writefln("Caught");
// Unrelated: If you're not familiar with the curly braces in
// the for loop, see the Note under "The sections of the for
// loop" section at http://ddili.org/ders/d.en/for.html
for ({ size_t i; Throwable ex = original; } ex; ex = ex.next,
++i) {
writeln(" ".replicate(i), ex.msg);
}
}
}
throwing 'TestException: 0'
throwing 'TestException: 1'
throwing 'TestException: 2'
throwing 'TestException: 3'
throwing 'TestException: 4'
Caught
TestException: 0
TestException: 1
TestException: 2
TestException: 3
TestException: 4
Make errorIndex something other than -1 e.g. 3 and you will see that the
Exception cannot be caught.
size_t errorIndex = 3;
You get the usual stack trace of an uncaught exception.
throwing 'TestException: 0'
throwing 'TestException: 1'
throwing 'TestException: 2'
throwing 'TestError: 3'
throwing 'TestException: 4'
deneme.TestError@(0): TestError: 3
----------------
[...]
Then, replace Exception with Error in the catch clause, and you will see
that Error is again caught. (Side note: Errors are not supposed to be
caught by programs because the whole state of the program is in question.)
catch (Error original) { // <-- Now Error
// ...
}
You will see that Error is in its own chain. It will contain just Error
3 and Error 4:
throwing 'TestException: 0'
throwing 'TestException: 1'
throwing 'TestException: 2'
throwing 'TestError: 3'
throwing 'TestException: 4'
Caught
TestError: 3
TestException: 4
Now you would hope to get the original bypassed Exception chain with the
following code
writefln("The bypassed exception was '%s'",
original.bypassedException);
But bypassedException member of Error is always null. Bug?
Thank you,
Ali