[Haskell-cafe] C++ exception (from *.so) catchable by Haskell??

Nick Rudnick nick.rudnick at gmail.com
Sun Feb 16 03:39:24 UTC 2014


>
>
>
> I have to admit that reading your messages has left me wondering what
> exactly
> it is that you are trying to do? What exactly is the problem that you are
> trying to solve?
>
You exactly got the point (below)  with "Your question is how to integrate
C++ code that might throw exceptions into Haskell via FFI, right?".

The only thing I am worried about is that, due to lacking experience, I
might introduce unnecessary runtime overhead, as performance is critical. I
don't want to disimprove.


>  > I see the solution isn't as easy as just replacing e.g.
>  >
>  > void myUnexpected () {
>  >   std::cerr << "unexpected called\n";
>  >   throw 0;
>  > }
>  >
>  > by
>  >
>  > void myUnexpected () {
>  >   std::cerr << "unexpected called\n";
>  > }
>
> I'm not sure whether the purpose of std::unexpected_handler() has become
> clear.
> That function is not supposed to handle exceptions in the sense that it
> makes
> the exception "go away" so that normal program flow can continue. Its
> purpose
> is to translate an unexpected exception -- which the program cannot handle
> --
> into a different one that the program can handle. Maybe this quote from [1]
> clarifies the matter:
>
>  | A user-defined std::unexpected_handler is expected to either terminate
> the
>  | program or throw an exception. If it throws an exception, one of the
>  | following three situations may be encountered:
>  |
>  |   1) the exception thrown by std::unexpected_handler satisfies the
> dynamic
>  |      exception specification that was violated earlier. The new
> exception is
>  |      allowed to escape the function and stack unwinding continues.
>  |
>  |   2) the exception thrown by std::unexpected_handler still violates the
>  |      exception specification:
>  |
>  |       a) however, the exception specification allows
> std::bad_exception: the
>  |          thrown exception object is destroyed, and std::bad_exception is
>  |          constructed by the C++ runtime and thrown instead.
>  |
>  |       b) the exception specification does not allow std::bad_exception:
>  |          std::terminate() is called.
>
> This means that the second myUnexpected() function from above is actually
> illegal in this context, because it neither throws an exception nor does it
> terminate the program.

What a delicate question... :-)) :-)) :-)) Better I choose my words
careful... Hmmm... certainly... In my case, it's failed DB queries that may
be caused by failed SQL queries in a backend behind the C++ code; and as
far as I can judge, everything is already handled neatly with no collateral
damage to be feared for – roughly, these C++ exceptions say that the SQL
code wasn't executed – in (a possible) interactive mode meaning merely
"please repeat that query correctly...".

But currently, this appears somewhat complicated by
(1) termination of the code
(2) quite terse messages (i.e., I am interested in better debug
capabilities, too)

By reading Alexander's link to
http://www.cplusplus.com/reference/exception/set_unexpected/, I got the
impression that there is reasonable chance there is a simple mechanism
behind set_unexpected(...) allows replacing some default code leading to
termination by arbitrary code – very attractive under these circumstances
–, and facing the question what's the meaning of 'illegal' was second to
this...

Anyway, this round went to Murphy – or at least I do not see a way to get
the termination avalanche stopped yet.

>
>  > The test code I have chosen for learning about the problem is hsqml by
> Robin
>  > Kay, which I consider to be very well done, usually injecting into
>  > HsQMLManager.{cpp|h}.hsqml_init(...),
>  >
>  > extern "C"
>  > void hsqml_init(void (*freeFun)(HsFunPtr), void
> (*freeStable)(HsStablePtr) ) throw() {
>  >   std::set_unexpected (myunexpected);
>  >   throw runtime_error("OOOPS...");
>  >   ...
>  > }
>
> I am not sure what exactly the intention behind that code snippet is. I've
> looked into the hsqml source at [2], and the hsqml_init() function there
> doesn't look like that.
>
Certainly, as lines were injected by me (I guess I mentioned at 1st mail)
for learning about the problem – with hsqml being needed as a scaffold for
this.


>
>  > What puzzles me currently is that, by the descriptions, I would expect
>  > that terminate() actually is replaced by std::cerr, so that the
>  > termination displayed in the result happens afterwards – but where??
>
> I am not sure what you mean by that statement. std:cerr is an object, so it
> cannot replace std::terminate(), which is a function.
>
 Please excuse: s/std:cerr/std:cerr.../

>
>  > In regard of what's my question, there should be something like a
>  > common/best practice, shouldn't it?
>
> Your question is how to integrate C++ code that might throw exceptions into
> Haskell via FFI, right? Please correct me if that's not the case.
>
Definitely, modulo performance/overhead.

>
> There is no one true way to accomplish that. Since you cannot catch or
> throw
> C++ exceptions in Haskell, you'll probably have to pass them from C++ to
> Haskell manually as a value. For example, the C++ function
>
>   int do_stuff() { ... }
>
> would need a wrapper like this one:
>
>   enum exception_type { none = 0, runtime_error, logic_error, unknown };
>
>   struct either_exception_or_int
>   {
>     exception_type err;
>     int val;
>   };
>
>   void do_stuff_(either_exception_or_int * result) throw()
>   {
>     try
>     {
>       result->err = none;
>       result->val = do_stuff();
>     }
>     catch(std::runtime_error const &)   { result->err = runtime_error; }
>     catch(std::logic_error const &)     { result->err = logic_error; }
>     catch(...)                          { result->err = unknown; }
>   }
>
> Now, on the Haskell side, you'd import do_stuff_() via FFI, and then write
> another wrapper
>
>   do_stuff :: IO Int
>   do_stuff = alloca $ \result -> do
>     do_stuff_ result
>     val <- peek result
>     either throwCxxError return val
>
>   throwCxxError :: CxxExceptionType -> IO a
>   throwCxxError Runtime_error = throwIO ...
>   throwCxxError ...
>
> to throw an appropriate Haskell exception that corresponds to the C++
> exception
> type.
>
You exactly concretized the 'Either' approach sketched in my mail, though I
would have tried to
(1) get a union instead of a struct for `either_exception_or_int'
(2) use pointers for err/val.
What I am worried about is that exactly this might result in inappropriate
overhead.

This directly leads to the other suggestion of my mail; to, instead of a
union of 2 pointers, let `either_exception_or_int' be just a pointer –
somewhat opaque for the Haskell side, which still might pipeline it very
efficiently from here to there, while it would be possible to C++ to
resolve the pointer addresses.

So with my 'illegal' one, I see 3 approaches yet.

I'm not sure whether anybody has done something like that before, i.e. I
> cannot
> refer you to a concrete Haskell project that demonstrates this technique
> with
> real-world code.
>
[?]

 > As Alexander states, there is a pleasing zero runtime approach with C++
>  > exceptions.
>
> I thought Alexander said the exact opposite, i.e. that C++ does *not* have
> zero
> overhead exceptions?
>
I referred to his mail just incoming when I answered to you (2014-2-14
9:11, "One unmentioned fact is that the exception mechanism in C++ is
designed to allow for implementations to have zero runtime cost. ...") –
what he addresses makes me quite less worried that catching C++ exceptions
themselves in the FFI would introduce performance issues, than
wrapping/unwrapping with Either & Co.

Cheers, Nick
-------------- next part --------------
An HTML attachment was scrubbed...
URL: <http://www.haskell.org/pipermail/haskell-cafe/attachments/20140216/c28c32cf/attachment.html>
-------------- next part --------------
A non-text attachment was scrubbed...
Name: 33A.gif
Type: image/gif
Size: 581 bytes
Desc: not available
URL: <http://www.haskell.org/pipermail/haskell-cafe/attachments/20140216/c28c32cf/attachment.gif>


More information about the Haskell-Cafe mailing list