digitalmars.D - Exception chaining and collectException
- H. S. Teoh via Digitalmars-d (54/54) Aug 17 2017 Code:
- Walter Bright (12/12) Aug 17 2017 Chained exceptions are a good idea, but are more or less a disaster:
- Don Clugston (23/38) Aug 18 2017 Well, I wrote them, so I can explain that. The problem is that
- jmh530 (5/18) Aug 18 2017 I had actually tested the above on Windows with DMD 2.075.1 and
- Walter Bright (7/15) Aug 18 2017 Thanks for the explanation. When I decided to support Dwarf exceptions, ...
- Steven Schveighoffer (4/19) Aug 18 2017 If we are to remove them, what happens when exceptions would
- Walter Bright (4/5) Aug 18 2017 In C++, throwing an exception while unwinding is a fatal error.
- Nemanja Boric (9/13) Aug 19 2017 Well, you still can throw it, but you're not allowed to let it
- H. S. Teoh via Digitalmars-d (13/23) Aug 21 2017 This was what I was trying to do: wrap some code in a try-catch in the
- =?UTF-8?Q?Ali_=c3=87ehreli?= (5/9) Aug 21 2017 I don't know whether C++11 changed matters but according to popular
- Nemanja Boric (4/17) Aug 22 2017 Rationale for changing this in C++17 is actually comming from
- Nemanja Boric (3/24) Aug 22 2017 Sorry, on the phone, so I've pasted wrong link:
- =?UTF-8?Q?Ali_=c3=87ehreli?= (4/6) Aug 21 2017 I caught (!) the same or similar behavior last year:
Code: -------- import std.exception : collectException; import std.stdio; class MyException : Exception { this() { super("MYMY"); } } void f() { throw new MyException(); } struct S { ~this() { auto e = collectException!MyException(f()); writefln("Collected: %s (%s)", typeid(e).toString, e.msg); } void method() { throw new Exception("Dumb error"); } } void main() { try { S s; s.method(); } catch (Exception e) { writefln("Caught: %s (%s) (next=%s)", typeid(e).toString, e.msg, e.next ? e.next.toString : "null"); } } -------- Expected output: collectException should collect MyException while "Dumb error" is in transit, and the output should contain a "Collected:" line. Actual behaviour: collectException doesn't work as advertised; MyException gets chained to the Exception in transit, and the "Collected:" line is never printed. If we change the collectException call to: auto e = collectException!Exception(f()); then it *does* work as advertised: the MyException instance is not chained, but is correctly collected by collectException. Why??? The code in question is reduced from a larger project where the dtor needs to do some non-trivial cleanup, but needs to ignore certain errors that may occur during cleanup. So it needs collectException to catch only certain subclasses of Exception, rather than all Exceptions. But the above inconsistent behaviour hampers this. Investigating the implementation of collectException, it seems that all it does is to use a try-catch block to catch an exception of the requested type. So the question becomes, why does the catch block *not* catch the instance of MyException when another exception is in transit?! T -- Gone Chopin. Bach in a minuet.
Aug 17 2017
Chained exceptions are a good idea, but are more or less a disaster: 1. No other language does chained exceptions 2. Attempting to hammer D chained exceptions into other language schemes (such as C++) makes for lots of unfun hours attempting to decode undocumented behavior in those other schemes 3. Makes D exceptions incompatible with other language exceptions and their infrastructure 4. Are incomprehensibly implemented (I defy anyone to explain how the test cases in the test suite are actually supposed to work) 5. Are more or less incompatible with non-GC memory allocation I'd like to remove them from D. I recommend *not* designing any program that requires them.
Aug 17 2017
On Friday, 18 August 2017 at 03:31:38 UTC, Walter Bright wrote:Chained exceptions are a good idea, but are more or less a disaster: 1. No other language does chained exceptions 2. Attempting to hammer D chained exceptions into other language schemes (such as C++) makes for lots of unfun hours attempting to decode undocumented behavior in those other schemes 3. Makes D exceptions incompatible with other language exceptions and their infrastructure 4. Are incomprehensibly implemented (I defy anyone to explain how the test cases in the test suite are actually supposed to work)Well, I wrote them, so I can explain that. The problem is that the idea that you can form a "chain" of exceptions turns out to be naive. What if a chained exception needs to get chained to another chained exception? And that then needs to be chained to another exception? It forms a tree! That's why the test cases are so complicated. So to a large extent, this extremely obscure corner case destroys the elegance of the concept. Secondly, exception handling in windows is practically undocumented. Certainly it's not documented in a single place. When I began to implement it, I feared it might be impossible. There isn't any guarantee that exception chaining can actually be implemented on all platforms.5. Are more or less incompatible with non-GC memory allocation I'd like to remove them from D. I recommend *not* designing any program that requires them.I invested quite a lot personally in implementing chained exceptions. But I agree with you. I was actually quite proud that I worked out the nasty corner cases during the initial implementation. As far as I can tell, problems with chained exceptions are not because of bugs and implementation issues, but because of problems with the concept itself. I think it's just a bit too clever.
Aug 18 2017
On Friday, 18 August 2017 at 09:09:47 UTC, Don Clugston wrote:Secondly, exception handling in windows is practically undocumented. Certainly it's not documented in a single place. When I began to implement it, I feared it might be impossible. There isn't any guarantee that exception chaining can actually be implemented on all platforms.I had actually tested the above on Windows with DMD 2.075.1 and got the expected behavior, not the buggy behavior.I invested quite a lot personally in implementing chained exceptions. But I agree with you. I was actually quite proud that I worked out the nasty corner cases during the initial implementation. As far as I can tell, problems with chained exceptions are not because of bugs and implementation issues, but because of problems with the concept itself. I think it's just a bit too clever.Do you mind pointing me in the direction of where chained exceptions are explained?
Aug 18 2017
On 8/18/2017 2:09 AM, Don Clugston wrote:I invested quite a lot personally in implementing chained exceptions. But I agree with you. I was actually quite proud that I worked out the nasty corner cases during the initial implementation. As far as I can tell, problems with chained exceptions are not because of bugs and implementation issues, but because of problems with the concept itself. I think it's just a bit too clever.Thanks for the explanation. When I decided to support Dwarf exceptions, I spent a lot of time trying to match that behavior. We've all invested lots of time in things that didn't pay off. We mustn't get trapped by the sunk cost fallacy: https://en.wikipedia.org/wiki/Sunk_cost and I'm glad you're ok with that!
Aug 18 2017
On Friday, 18 August 2017 at 03:31:38 UTC, Walter Bright wrote:Chained exceptions are a good idea, but are more or less a disaster: 1. No other language does chained exceptions 2. Attempting to hammer D chained exceptions into other language schemes (such as C++) makes for lots of unfun hours attempting to decode undocumented behavior in those other schemes 3. Makes D exceptions incompatible with other language exceptions and their infrastructure 4. Are incomprehensibly implemented (I defy anyone to explain how the test cases in the test suite are actually supposed to work) 5. Are more or less incompatible with non-GC memory allocation I'd like to remove them from D. I recommend *not* designing any program that requires them.If we are to remove them, what happens when exceptions would normally chain? -Steve
Aug 18 2017
On 8/18/2017 5:07 AM, Steven Schveighoffer wrote:If we are to remove them, what happens when exceptions would normally chain?In C++, throwing an exception while unwinding is a fatal error. More information: https://stackoverflow.com/questions/130117/throwing-exceptions-out-of-a-destructor
Aug 18 2017
On Friday, 18 August 2017 at 22:51:35 UTC, Walter Bright wrote:On 8/18/2017 5:07 AM, Steven Schveighoffer wrote:Well, you still can throw it, but you're not allowed to let it escape the destructor (you need to catch them before they would chain). C++ also provides a way to inspect if you're in the middle of the stack unwinding caused by an exception, to make this a bit more controllable, and I would think we should provide the similar primitive: http://en.cppreference.com/w/cpp/error/uncaught_exception.If we are to remove them, what happens when exceptions would normally chain?In C++, throwing an exception while unwinding is a fatal error.
Aug 19 2017
On Sat, Aug 19, 2017 at 08:58:51PM +0000, Nemanja Boric via Digitalmars-d wrote:On Friday, 18 August 2017 at 22:51:35 UTC, Walter Bright wrote:This was what I was trying to do: wrap some code in a try-catch in the dtor so that any exceptions thrown won't escape the dtor. However, the current inconsistent behaviour is making this difficult. The same dtor behaves differently depending on whether it was called from a normal end of scope, or while an Exception is in transit. I.e., when called normally, the catch clause catches MyException, but when another Exception is in transit, the catch clause fails to catch MyException (yet it does catch the base class Exception, a rather strange behaviour). T -- The most powerful one-line C program: #include "/dev/tty" -- IOCCCOn 8/18/2017 5:07 AM, Steven Schveighoffer wrote:Well, you still can throw it, but you're not allowed to let it escape the destructor (you need to catch them before they would chain).If we are to remove them, what happens when exceptions would normally chain?In C++, throwing an exception while unwinding is a fatal error.
Aug 21 2017
On 08/19/2017 01:58 PM, Nemanja Boric wrote:C++ also provides a way to inspect if you're in the middle of the stack unwinding caused by an exception, to make this a bit more controllable, and I would think we should provide the similar primitive: http://en.cppreference.com/w/cpp/error/uncaught_exception.I don't know whether C++11 changed matters but according to popular C++98 wisdom, we were told "Don't use [std::uncaught_exception]": www.gotw.ca/gotw/047.htm Ali
Aug 21 2017
On Monday, 21 August 2017 at 20:15:53 UTC, Ali Çehreli wrote:On 08/19/2017 01:58 PM, Nemanja Boric wrote:Rationale for changing this in C++17 is actually comming from Herb Sutter and it is referring to gotw47: http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2013/n3614.pdfC++ also provides a way to inspect if you're in the middle of the stack unwinding caused by an exception, to make this a bit more controllable, and I would think we should provide the similar primitive: .I don't know whether C++11 changed matters but according to popular C++98 wisdom, we were told "Don't use [std::uncaught_exception]": www.gotw.ca/gotw/047.htm Ali
Aug 22 2017
On Tuesday, 22 August 2017 at 07:03:03 UTC, Nemanja Boric wrote:On Monday, 21 August 2017 at 20:15:53 UTC, Ali Çehreli wrote:Sorry, on the phone, so I've pasted wrong link: http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2014/n4152.pdfOn 08/19/2017 01:58 PM, Nemanja Boric wrote:Rationale for changing this in C++17 is actually comming from Herb Sutter and it is referring to gotw47: http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2013/n3614.pdfC++ also provides a way to inspect if you're in the middle of the stack unwinding caused by an exception, to make this a bit more controllable, and I would think we should provide the similar primitive: .I don't know whether C++11 changed matters but according to popular C++98 wisdom, we were told "Don't use [std::uncaught_exception]": www.gotw.ca/gotw/047.htm Ali
Aug 22 2017
On 08/17/2017 02:48 PM, H. S. Teoh via Digitalmars-d wrote:So the question becomes, why does the catch block *not* catch the instance of MyException when another exception is in transit?!I caught (!) the same or similar behavior last year: https://issues.dlang.org/show_bug.cgi?id=16177 Ali
Aug 21 2017