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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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