www.digitalmars.com         C & C++   DMDScript  

digitalmars.D - Catching C++ Exceptions in D

reply Walter Bright <newshound2 digitalmars.com> writes:
We have a design now, driven by:

1. compatibility with best practice exceptions in C++ (i.e. never catch by 
value, etc.)

2. minimizing implementation difficulty

3. fitting in with D semantics

4. pushing as much as we can into the C++ compiler

----------------------------------------------------------

C++ exceptions cannot be thrown from D. If you must throw a C++ exception,
write 
and call a C++ function to do it.

C++ rethrows as well need to be done by calling a C++ function to do it.

D code can only catch C++ exceptions declared as:

     extern (C++) class Identifier { ... }

Best practice in C++ is catching by const&, and D's classes fit right in with
that.

At the exit of a catch clause, the destructor on the caught C++ exception will 
be run, as would be expected by C++ programmers.

Because of running the destructors, C++ exceptions cannot be caught in  safe
code.

Function bodies cannot mix catching C++ and D exceptions. (The reason is C++ 
catch types need to be distinguished from D catch types, and the most 
straightforward method to deal with that is have a different 'personality' 
function for functions that catch C++ exceptions.) However, nested functions
can 
catch different ones than their enclosing function.
Jan 05 2016
next sibling parent Daniel N <ufo orbiting.us> writes:
On Tuesday, 5 January 2016 at 17:23:38 UTC, Walter Bright wrote:
 Function bodies cannot mix catching C++ and D exceptions.
Sounds good(assuming one gets a compilation error when this rule is broken).
Jan 05 2016
prev sibling next sibling parent reply Jakob Ovrum <jakobovrum gmail.com> writes:
On Tuesday, 5 January 2016 at 17:23:38 UTC, Walter Bright wrote:
 We have a design now, driven by:

 1. compatibility with best practice exceptions in C++ (i.e. 
 never catch by value, etc.)

 2. minimizing implementation difficulty

 3. fitting in with D semantics

 4. pushing as much as we can into the C++ compiler

 ----------------------------------------------------------

 C++ exceptions cannot be thrown from D. If you must throw a C++ 
 exception, write and call a C++ function to do it.
Because C++-throw copies the exception and thus slices base class references, this is actually quite inconvenient. There's no One Helper Function that can handle a whole swath of cases. Just wanted to mention it, not saying this should be an important or priority feature, it's just an inconvenience after all.
 D code can only catch C++ exceptions declared as:

     extern (C++) class Identifier { ... }

 Best practice in C++ is catching by const&, and D's classes fit 
 right in with that.
Well, except for the const part. D exceptions are completely broken when it comes to const and immutable. It seems to have been overlooked during the transition to D2.
 At the exit of a catch clause, the destructor on the caught C++ 
 exception will be run, as would be expected by C++ programmers.

 Because of running the destructors, C++ exceptions cannot be 
 caught in  safe code.
Nice.
 Function bodies cannot mix catching C++ and D exceptions. (The 
 reason is C++ catch types need to be distinguished from D catch 
 types, and the most straightforward method to deal with that is 
 have a different 'personality' function for functions that 
 catch C++ exceptions.) However, nested functions can catch 
 different ones than their enclosing function.
Nice. Thanks for doing this. I'm excited about C++ interop. There was a project called OpenMorrowind which dropped D1+C++ in favour of just C++ because the C interface was too tedious. I bet if they had what we have now they wouldn't have done that (assuming we fix the mangling bugs for C++ function templates and then provide stdc++ bindings). Switching to DWARF has another benefit - it allows throwing D exceptions past C stack frames. Some people seem to think this is always wrong, but some C libraries are designed to support throwing or long jumping from certain callbacks, including libev and liblua. This tremendously helps the usability of D wrappers around such libraries. Currently I work around it by providing custom-compiled binaries of the C libraries with intact stack frames. This is also cause to be sad about our DWARF support being limited to Linux64. Anyway, thanks!
Jan 05 2016
next sibling parent reply Walter Bright <newshound2 digitalmars.com> writes:
On 1/5/2016 10:22 AM, Jakob Ovrum wrote:
 C++ exceptions cannot be thrown from D. If you must throw a C++ exception,
 write and call a C++ function to do it.
Because C++-throw copies the exception and thus slices base class references, this is actually quite inconvenient. There's no One Helper Function that can handle a whole swath of cases. Just wanted to mention it, not saying this should be an important or priority feature, it's just an inconvenience after all.
It's just a limitation for now in order to get things moving.
Jan 05 2016
parent reply Jacob Carlborg <doob me.com> writes:
On 2016-01-05 19:49, Walter Bright wrote:

 It's just a limitation for now in order to get things moving.
What happens if one just calls "__cxa_throw"? -- /Jacob Carlborg
Jan 05 2016
parent Walter Bright <newshound2 digitalmars.com> writes:
On 1/5/2016 1:19 PM, Jacob Carlborg wrote:
 On 2016-01-05 19:49, Walter Bright wrote:

 It's just a limitation for now in order to get things moving.
What happens if one just calls "__cxa_throw"?
I don't know.
Jan 05 2016
prev sibling parent Jakob Ovrum <jakobovrum gmail.com> writes:
On Tuesday, 5 January 2016 at 18:22:56 UTC, Jakob Ovrum wrote:
 On Tuesday, 5 January 2016 at 17:23:38 UTC, Walter Bright wrote:
 D code can only catch C++ exceptions declared as:

     extern (C++) class Identifier { ... }

 Best practice in C++ is catching by const&, and D's classes 
 fit right in with that.
Well, except for the const part. D exceptions are completely broken when it comes to const and immutable. It seems to have been overlooked during the transition to D2.
Of course, C++ doesn't have immutable, so this isn't really an issue in practice for C++ exceptions.
Jan 05 2016
prev sibling next sibling parent reply Elie Morisse <syniurge gmail.com> writes:
On Tuesday, 5 January 2016 at 17:23:38 UTC, Walter Bright wrote:
 Function bodies cannot mix catching C++ and D exceptions. (The 
 reason is C++ catch types need to be distinguished from D catch 
 types, and the most straightforward method to deal with that is 
 have a different 'personality' function for functions that 
 catch C++ exceptions.)
why not distinguish C++ exceptions from D ones in the personality routine?
Jan 05 2016
parent reply Walter Bright <newshound2 digitalmars.com> writes:
On 1/5/2016 10:51 AM, Elie Morisse wrote:
 why not distinguish C++ exceptions from D ones in the personality routine?
How?
Jan 05 2016
next sibling parent reply Jacob Carlborg <doob me.com> writes:
On 2016-01-05 21:07, Walter Bright wrote:

 How?
There's something called "__cxa_current_exception_type" [1], can that be of use? [1] http://libcxxabi.llvm.org/spec.html -- /Jacob Carlborg
Jan 05 2016
parent Walter Bright <newshound2 digitalmars.com> writes:
On 1/5/2016 1:22 PM, Jacob Carlborg wrote:
 On 2016-01-05 21:07, Walter Bright wrote:

 How?
There's something called "__cxa_current_exception_type" [1], can that be of use? [1] http://libcxxabi.llvm.org/spec.html
That only works with C++ types, not D types.
Jan 05 2016
prev sibling parent reply Elie Morisse <syniurge gmail.com> writes:
On Tuesday, 5 January 2016 at 20:07:11 UTC, Walter Bright wrote:
 On 1/5/2016 10:51 AM, Elie Morisse wrote:
 why not distinguish C++ exceptions from D ones in the 
 personality routine?
How?
Are you aware of https://syniurgeblog.wordpress.com/2015/11/20/calypso-catching-cpp-exceptions-in-d/? For DMD if the personality functions sees the C++ exception class (3rd arg passed to the personality func) would it be hard to make it look for C++ catch clauses? With Calypso those catch clauses are std::type_info pointers wrapped inside a D class so that cast() is used to differentiate D catch clauses from C++ ones in the action table, and the personality function match those std::type_info against the one from the C++ exception header by calling the virtual function type_info::__do_catch(type_info*). A single personality routine handles both D and C++ exceptions, and I don't think having a different one for C++ exceptions would make things much easier. The tricky part for DMD is probably the std::type_info generation.
Jan 05 2016
parent Walter Bright <newshound2 digitalmars.com> writes:
On 1/5/2016 2:58 PM, Elie Morisse wrote:
 On Tuesday, 5 January 2016 at 20:07:11 UTC, Walter Bright wrote:
 On 1/5/2016 10:51 AM, Elie Morisse wrote:
 why not distinguish C++ exceptions from D ones in the personality routine?
How?
Are you aware of https://syniurgeblog.wordpress.com/2015/11/20/calypso-catching-cpp-exceptions-in-d/?
No, thanks for pointing it out. Your solution is clever. I'll have to think about which method is better. Also, catch (C++)(ref exception e) the (C++) seems redundant. The compiler can look at the type of e, and determine if it is C++ or not.
Jan 05 2016
prev sibling next sibling parent Jacob Carlborg <doob me.com> writes:
On 2016-01-05 18:23, Walter Bright wrote:

 C++ rethrows as well need to be done by calling a C++ function to do it.
Seems to be easy with "__cxa_rethrow", takes no arguments and doesn't return anything. -- /Jacob Carlborg
Jan 05 2016
prev sibling parent reply Jakob Ovrum <jakobovrum gmail.com> writes:
On Tuesday, 5 January 2016 at 17:23:38 UTC, Walter Bright wrote:
 At the exit of a catch clause, the destructor on the caught C++ 
 exception will be run, as would be expected by C++ programmers.
Does this work with rethrow? What if a D exception is thrown from a C++ catch block - will the C++ exception still be destroyed properly?
Jan 05 2016
next sibling parent Jakob Ovrum <jakobovrum gmail.com> writes:
On Tuesday, 5 January 2016 at 21:30:21 UTC, Jakob Ovrum wrote:
 On Tuesday, 5 January 2016 at 17:23:38 UTC, Walter Bright wrote:
 At the exit of a catch clause, the destructor on the caught 
 C++ exception will be run, as would be expected by C++ 
 programmers.
Does this work with rethrow? What if a D exception is thrown from a C++ catch block - will the C++ exception still be destroyed properly?
To clarify, I mean a catch block in D code that catches as C++ exception.
Jan 05 2016
prev sibling parent reply Walter Bright <newshound2 digitalmars.com> writes:
On 1/5/2016 1:30 PM, Jakob Ovrum wrote:
 On Tuesday, 5 January 2016 at 17:23:38 UTC, Walter Bright wrote:
 At the exit of a catch clause, the destructor on the caught C++ exception will
 be run, as would be expected by C++ programmers.
Does this work with rethrow? What if a D exception is thrown from a C++ catch block - will the C++ exception still be destroyed properly?
My understanding is that rethrow invokes the copy constructor, so the original can still be destroyed.
Jan 05 2016
parent Andrei Alexandrescu <SeeWebsiteForEmail erdani.org> writes:
On 01/05/2016 06:56 PM, Walter Bright wrote:
 On 1/5/2016 1:30 PM, Jakob Ovrum wrote:
 On Tuesday, 5 January 2016 at 17:23:38 UTC, Walter Bright wrote:
 At the exit of a catch clause, the destructor on the caught C++
 exception will
 be run, as would be expected by C++ programmers.
Does this work with rethrow? What if a D exception is thrown from a C++ catch block - will the C++ exception still be destroyed properly?
My understanding is that rethrow invokes the copy constructor, so the original can still be destroyed.
To clarify what C++ does, consider: try { ... } catch (std::exception& e) { throw e; } This throws a copy of e and is almost always not the desired/expected behavior because the original dynamic type of e (which may be a class derived from std::exception) is lost. Now consider: try { ... } catch (std::exception& e) { throw; } In this case no copy is created. The same exact dynamic object continues to be thrown up the chain. Andrei
Jan 06 2016