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