Thanks all. My summary here differs a bit though:

1. The point that a longjump does not necessarily represent an error
is crucial here. That's the rationale behind Lionel's implementation
of this exception. My understanding then is that client packages
should *never ever* catch it, and thus it shouldn't inherit from
std::exception.

2. UnwindProtect is a mechanism introduced in R back in 2017 for fast
and safe C++ stack unwinding, so I think it's time we stick to it.
When enabled, Rcpp leverages this via Rcpp_fast_eval. Before that,
Rcpp_eval was/is... kind of hackish (no offense intended; it was the
best thing to do before R properly supported C++ via UnwindProtect),
because it relied on tryCatch, which sometimes resulted in several
tryCatch stacked together. Rcpp_fast_eval is called in a number of
places in Rcpp, and thus client packages would greatly benefit from
finally switching to UnwindProtect, including V8.

3. But then, V8 *really needs* to catch R errors in the JS virtual
machine. So the solution... is to add *a* tryCatch in the proper place
(not a matrioska of tryCatches, as it happens without UnwindProtect).
And this is exactly what Jeroen did [1]. I think that the solution is
brilliant and the proper way to go here (as it happens, that tryCatch
was in place before, for other reasons I suppose, and now it has been
repurposed to properly catch errors too).

4. Another way to address this was mentioned by Lionel: Rcpp_eval is
still there. Arguably though, this interface is not very
user-friendly, and Rcpp::Function is much nicer. I don't think that
Rcpp::Function should switch to Rcpp_eval, but we could offer some
kind of Rcpp::TryCatchFunction (ok, the name can be improved) that
uses Rcpp_eval, or some kind of wrapper class that forces
Rcpp::Function to use Rcpp_eval instead.

[1] https://github.com/jeroen/V8/commit/3258ce61dd02eaed51edef5391dc5afcd456d16c

Iñaki


On Mon, 7 Feb 2022 at 03:11, Kevin Ushey <kevinus...@gmail.com> wrote:
>
> Thanks, I think I understand the issue better now. Ultimately, it comes down 
> to the fact that UnwindProtect doesn't really allow handling of R conditions 
> in the "regular" way as e.g. tryCatch() does; instead, it gives us just 
> enough to properly unwind the C++ stack when an R error occurs. If I can 
> summarize:
>
> 1. Client packages can catch the Rcpp LongjumpException and handle it 
> themselves if they need to, but it's not obvious how to do this correctly.
> 2. R error messages are printed by R when the error is emitted.
> 3. It's not clear to the LongJumpException handler what R error triggered the 
> longjmp exception.
>
> In particular, for (1), Rcpp is normally responsible for unprotecting its 
> unwind token, and then continuing the unwind:
>
> https://github.com/RcppCore/Rcpp/blob/1c8a1946db56e4d8041593906eddcb0da8ba07a0/inst/include/Rcpp/exceptions.h#L148-L157
>
> If we want to make it safe for client packages to catch these exceptions, 
> we'd need to provide a helper for cleaning up Rcpp's unwind state, or make 
> that happen automatically. (Maybe the token's protection status could be 
> managed as part of the exception's lifetime? Not sure.) However, the fact 
> that the LongjumpException needs special handling implies that it probably 
> shouldn't inherit from std::exception.
>
> For (2), I don't see a clean way of handling this beyond setting the 
> 'show.error.messages' option to false. Unfortunately, because UnwindProtect 
> is not a "real" R condition handler, it gets processed only after the 
> "regular" R error machinery runs (which includes printing the error before 
> actually jumping).
>
> I'm similarly not aware of any solution for (3).
>
> In other words, my understanding is that if you're a client of Rcpp and you 
> want to be able to catch and handle R errors at the C++ level, 
> UnwindProtect() isn't the right tool -- you'll want a proper tryCatch() 
> handler.
>
> It does also imply (as had been shown) that switching to unwind-protect would 
> be a behavior change in Rcpp, which may not be ideal.
>
> Thanks,
> Kevin
>
>
>
>
> On Sun, Feb 6, 2022 at 9:39 AM Jeroen Ooms <jeroeno...@gmail.com> wrote:
>>
>> On Sun, Feb 6, 2022 at 6:25 PM Kevin Ushey <kevinus...@gmail.com> wrote:
>> >
>> > If I tweak your example package code so that all exceptions are caught via 
>> > a catch (...) {} block, I can see something like:
>> >
>> > > uptest::uptest()
>> > Error in (function ()  : Ouch from R
>> > Caught some other exception.
>> >
>> > The fact that we're still printing the R error message seems undesirable, 
>> > but it looks like the exception can be caught -- just not via 
>> > std::exception.
>>
>> Yes that is also what Iñaki and me alluded to above. But I think this
>> way, what we are catching is not the R error itself (which seems lost
>> after it was printed), but rather a token that tells the application
>> we should let Rcpp unwind all the way back to the R console. Which is
>> what happens if we don't catch it, then it makes sense. But if we _do_
>> want to handle the situation in C++, this doesn't give us much to work
>> with.
>
> _______________________________________________
> Rcpp-devel mailing list
> Rcpp-devel@lists.r-forge.r-project.org
> https://lists.r-forge.r-project.org/cgi-bin/mailman/listinfo/rcpp-devel



-- 
Iñaki Úcar
_______________________________________________
Rcpp-devel mailing list
Rcpp-devel@lists.r-forge.r-project.org
https://lists.r-forge.r-project.org/cgi-bin/mailman/listinfo/rcpp-devel

Reply via email to