digitalmars.D.learn - Error and Exception chaining
- Yuxuan Shui (5/5) Dec 12 2016 I read https://dlang.org/spec/statement.html, which told me that
- =?UTF-8?Q?Ali_=c3=87ehreli?= (113/118) Dec 12 2016 (Note: Looks like there is a bug regarding Error.bypassedException
- Yuxuan Shui (5/23) Dec 12 2016 But chaining Error to Error works just like chaining Exception to
- =?UTF-8?Q?Ali_=c3=87ehreli?= (13/36) Dec 12 2016 Currently yes. Now this line in my versatile :o) program:
- Yuxuan Shui (3/36) Dec 12 2016 I did some testing and bypassedException is null in 2.072.1, but
- Yuxuan Shui (4/49) Dec 12 2016 The unwind process seem to stop one level too early, causing
- Yuxuan Shui (8/60) Dec 12 2016 OK. I think I figured it out. catch(Error x) won't catch
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.
Dec 12 2016
(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
Dec 12 2016
Thanks a lot for the explanation! On Monday, 12 December 2016 at 22:01:54 UTC, Ali Çehreli wrote:(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:But chaining Error to Error works just like chaining Exception to Exception?[...]that Error[...]vague, and I'm[...]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.But bypassedException member of Error is always null. Bug?Did I just randomly found a bug?Thank you, Ali
Dec 12 2016
On 12/12/2016 02:08 PM, Yuxuan Shui wrote:Thanks a lot for the explanation! On Monday, 12 December 2016 at 22:01:54 UTC, Ali Çehreli wrote:Currently yes. Now this line in my versatile :o) program: if (n >= errorIndex) { Two Errors are chained: Caught TestError: 3 TestError: 4 However, there is the following ongoing thread claiming that it was a wrong decision: http://forum.dlang.org/post/o2n347$2i1g$1 digitalmars.com(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:But chaining Error to Error works just like chaining Exception to Exception?[...]that Error[...]vague, and I'm[...]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.From what I could graps from that much of documentation, yes, it seems to be a bug. AliBut bypassedException member of Error is always null. Bug?Did I just randomly found a bug?
Dec 12 2016
On Monday, 12 December 2016 at 22:13:59 UTC, Ali Çehreli wrote:On 12/12/2016 02:08 PM, Yuxuan Shui wrote:I did some testing and bypassedException is null in 2.072.1, but is not null in 2.070.2[...]wrote:Error.bypassedException[...]mechanism,[...]Error."[...]Exception,[...]otherwise[...]original[...]is the Error.[...][...]Exception to[...]Currently yes. Now this line in my versatile :o) program: if (n >= errorIndex) { Two Errors are chained: Caught TestError: 3 TestError: 4 However, there is the following ongoing thread claiming that it was a wrong decision: http://forum.dlang.org/post/o2n347$2i1g$1 digitalmars.com[...]From what I could graps from that much of documentation, yes, it seems to be a bug.Ali
Dec 12 2016
On Monday, 12 December 2016 at 22:35:22 UTC, Yuxuan Shui wrote:On Monday, 12 December 2016 at 22:13:59 UTC, Ali Çehreli wrote:The unwind process seem to stop one level too early, causing language_specific_data to be different, causing __dmd_personality_v0 to not chain exception into .bypassException.On 12/12/2016 02:08 PM, Yuxuan Shui wrote:I did some testing and bypassedException is null in 2.072.1, but is not null in 2.070.2[...]wrote:Error.bypassedException[...]mechanism,[...]Error."[...]Exception,[...]otherwise[...]original[...]is the Error.[...][...]Exception to[...]Currently yes. Now this line in my versatile :o) program: if (n >= errorIndex) { Two Errors are chained: Caught TestError: 3 TestError: 4 However, there is the following ongoing thread claiming that it was a wrong decision: http://forum.dlang.org/post/o2n347$2i1g$1 digitalmars.com[...]From what I could graps from that much of documentation, yes, it seems to be a bug.Ali
Dec 12 2016
On Tuesday, 13 December 2016 at 00:33:58 UTC, Yuxuan Shui wrote:On Monday, 12 December 2016 at 22:35:22 UTC, Yuxuan Shui wrote:OK. I think I figured it out. catch(Error x) won't catch TestException, so TestException 0,1,2 is not handled at main(). However TestError 3 (and TestExcepotion 4 which is chained to it) is handled at main(). And dmd won't put Throwables that are handled at different places together. This behavior seems reasonable. So maybe this is actually a bug is LDC?On Monday, 12 December 2016 at 22:13:59 UTC, Ali Çehreli wrote:The unwind process seem to stop one level too early, causing language_specific_data to be different, causing __dmd_personality_v0 to not chain exception into .bypassException.On 12/12/2016 02:08 PM, Yuxuan Shui wrote:I did some testing and bypassedException is null in 2.072.1, but is not null in 2.070.2[...]wrote:Error.bypassedException[...]mechanism,[...]Error."[...]Exception,[...]otherwise[...]original[...]is the Error.[...][...]Exception to[...]Currently yes. Now this line in my versatile :o) program: if (n >= errorIndex) { Two Errors are chained: Caught TestError: 3 TestError: 4 However, there is the following ongoing thread claiming that it was a wrong decision: http://forum.dlang.org/post/o2n347$2i1g$1 digitalmars.com[...]From what I could graps from that much of documentation, yes, it seems to be a bug.Ali
Dec 12 2016