Coder Social home page Coder Social logo

Comments (9)

Enchufa2 avatar Enchufa2 commented on May 27, 2024 4

And for completeness, note that you are still able to catch those errors in C++, but instead of std::exception in your reprex above, you need to catch Rcpp::LongjumpException. If you do this, please be sure to rethrow the exception, so that the unwind is completed. See #807 for a longer discussion.

library(Rcpp)

cppFunction(
  'void evalStopFunction(const Rcpp::Function& fn) {
    try {
      fn();
    } catch (const Rcpp::LongjumpException& e) {
      std::rethrow_exception(std::current_exception());
    } catch (...) {
      throw std::runtime_error("Unknown Error");
    }
  }'
)

fn <- function() stop("Test")
evalStopFunction(fn)
#> Error in (function () : Test

from rcpp.

kevinushey avatar kevinushey commented on May 27, 2024 2

For reference, some of the related discussion:

#1227 (comment)

Indeed, Rcpp no longer catches R errors and attempts to re-throw those as C++ exceptions, so code of the OP's form won't work as it did in previous builds of Rcpp. The consensus was that this was worth the breakage, since the amount of infrastructure around "safe" evaluation meant executing R code from Rcpp was very expensive.

from rcpp.

eddelbuettel avatar eddelbuettel commented on May 27, 2024

That ... strikes me as odd. I work with Rcpp all day and I surely do see errors caught and returned to R. Mind you the default and standard approach is to let Rcpp::stop() throw an exception that will get caught, converted and returned.
And that still works:

> Rcpp::cppFunction(r"[void foo() { Rprintf("Hi\n"); Rcpp::stop("Bye"); Rprintf("Gone\n"); } ]")
> foo()
Hi
Error: Bye
> 

Also are you aware that Rcpp injects try catch blocks for you? The above is not what compiles, try adding verbose=TRUE, rebuild=TRUE to the end of your cppFunction() call. The BEGIN_RCPP and END_RCPP get expanded.

Lastly, note the first item in the release notes. This may be what rattles you, and as noted you can turn it off.

Rcpp/inst/NEWS.Rd

Lines 36 to 43 in 3456999

\item Unwind protection is enabled by default (Iñaki in \ghpr{1225}).
It can be disabled by defining \code{RCPP_NO_UNWIND_PROTECT} before
including \code{Rcpp.h}. \code{RCPP_USE_UNWIND_PROTECT} is not checked
anymore and has no effect. The associated plugin \code{unwindProtect}
is therefore deprecated and will be removed in a future release.
\item The 'finalize' method for Rcpp Modules is now eagerly materialized,
fixing an issue where errors can occur when Module finalizers are run
(Kevin in \ghpr{1231} closing \ghit{1230}).

Finally, if you use your standard C++ exception handling in functions not modified by Rcpp Attributes for you convenience it likely still works, We do not generally muck with exceptions because that would be ... crazy.

from rcpp.

hsloot avatar hsloot commented on May 27, 2024

It seems that the behavior changed with d389a8a.

from rcpp.

eddelbuettel avatar eddelbuettel commented on May 27, 2024

That is precisely the issue in NEWS that I pointed out to you, and it was preceeded by lengthy discussion. Unlikely to be reverted; I invite you to use the available toggle to turn it off if you do not want that behaviour. We try to give you a choice.

from rcpp.

eddelbuettel avatar eddelbuettel commented on May 27, 2024

Yup.

Code

#define RCPP_NO_UNWIND_PROTECT 1
#include <Rcpp/Rcpp>

// [[Rcpp::export]]
void evalStopFunction(const Rcpp::Function& fn) {
  try {
    fn();
  } catch (const std::exception& e) {
    std::rethrow_exception(std::current_exception());
  } catch (...) {
    throw std::runtime_error("Unknown Error");
  }
}


/*** R
packageVersion("Rcpp")
fn <- function() stop("Test")
evalStopFunction(fn)
*/

Output

> Rcpp::sourceCpp("/tmp/issue1268.cpp")

> packageVersion("Rcpp")
[1] ‘1.0.10.5> fn <- function() stop("Test")

> evalStopFunction(fn)
Error in evalStopFunction(fn) : Evaluation error: Test.
> 

All good?

from rcpp.

hsloot avatar hsloot commented on May 27, 2024

Sorry, I sent my last comment before seeing your answer. Thanks for your example; I see that disabling unwind protect reverts to the original behavior. I will also have a look if that is an option for my actual code. However, I still find the changed behavior odd, since I would have expected that function evaluation errors throw a Rcpp::eval_error, deriving from std::exception, that I can catch. For me, it looks like the evaluation stop("Test") somehow bypasses the catch-block (see reprex below). If that is intended, please close the issue.

For a bit of background, the code I used for the reprex is a minimal working example of an actual use case, which is testing that exceptions generated by a C++ wrapper of R's C-API for numerical integration are thrown as intended. Rcpp is only used for convenience in testing the wrapper.

# RcppCore/[email protected]
library(Rcpp)

cppFunction(
  'void evalStopFunction(const Rcpp::Function& fn) {
    try {
      fn();
    } catch (...) {
      // ignore
    }
  }'
)

fn <- function() stop("Test")
evalStopFunction(fn)
#> Error in (function () : Test

Created on 2023-06-29 with reprex v2.0.2

Session info
sessioninfo::session_info()
#> ─ Session info ───────────────────────────────────────────────────────────────
#>  setting  value
#>  version  R version 4.3.1 (2023-06-16)
#>  os       macOS Ventura 13.4
#>  system   aarch64, darwin20
#>  ui       X11
#>  language (EN)
#>  collate  en_US.UTF-8
#>  ctype    en_US.UTF-8
#>  tz       Europe/Berlin
#>  date     2023-06-29
#>  pandoc   3.1.4 @ /opt/homebrew/bin/ (via rmarkdown)
#> 
#> ─ Packages ───────────────────────────────────────────────────────────────────
#>  package     * version date (UTC) lib source
#>  cli           3.6.1   2023-03-23 [1] CRAN (R 4.3.0)
#>  digest        0.6.31  2022-12-11 [1] CRAN (R 4.3.0)
#>  evaluate      0.21    2023-05-05 [1] CRAN (R 4.3.0)
#>  fastmap       1.1.1   2023-02-24 [1] CRAN (R 4.3.0)
#>  fs            1.6.2   2023-04-25 [1] CRAN (R 4.3.0)
#>  glue          1.6.2   2022-02-24 [1] CRAN (R 4.3.0)
#>  htmltools     0.5.5   2023-03-23 [1] CRAN (R 4.3.0)
#>  knitr         1.43    2023-05-25 [1] CRAN (R 4.3.0)
#>  lifecycle     1.0.3   2022-10-07 [1] CRAN (R 4.3.0)
#>  magrittr      2.0.3   2022-03-30 [1] CRAN (R 4.3.0)
#>  purrr         1.0.1   2023-01-10 [1] CRAN (R 4.3.0)
#>  R.cache       0.16.0  2022-07-21 [1] CRAN (R 4.3.0)
#>  R.methodsS3   1.8.2   2022-06-13 [1] CRAN (R 4.3.0)
#>  R.oo          1.25.0  2022-06-12 [1] CRAN (R 4.3.0)
#>  R.utils       2.12.2  2022-11-11 [1] CRAN (R 4.3.0)
#>  Rcpp        * 1.0.10  2023-01-22 [1] CRAN (R 4.3.0)
#>  reprex        2.0.2   2022-08-17 [1] CRAN (R 4.3.0)
#>  rlang         1.1.1   2023-04-28 [1] CRAN (R 4.3.0)
#>  rmarkdown     2.22    2023-06-01 [1] CRAN (R 4.3.0)
#>  rstudioapi    0.14    2022-08-22 [1] CRAN (R 4.3.0)
#>  sessioninfo   1.2.2   2021-12-06 [1] CRAN (R 4.3.0)
#>  styler        1.10.1  2023-06-05 [1] CRAN (R 4.3.0)
#>  vctrs         0.6.3   2023-06-14 [1] CRAN (R 4.3.0)
#>  withr         2.5.0   2022-03-03 [1] CRAN (R 4.3.0)
#>  xfun          0.39    2023-04-20 [1] CRAN (R 4.3.0)
#>  yaml          2.3.7   2023-01-23 [1] CRAN (R 4.3.0)
#> 
#>  [1] /Library/Frameworks/R.framework/Versions/4.3-arm64/Resources/library
#> 
#> ──────────────────────────────────────────────────────────────────────────────

from rcpp.

eddelbuettel avatar eddelbuettel commented on May 27, 2024

If Rcpp's convenience gets in your way, you can disable it (I showed you how) and/or do not use the wrapper creation (see my first comment) and/or do your own try/catch handling and/or write basic SEXP foo(SEXP, ....) and do.call() that,

We generally do what we do for a reason, and this change was fairly long in coming and fairly important for both performance and edge cases (catching exceptions across compilation units can get hairy).

from rcpp.

eddelbuettel avatar eddelbuettel commented on May 27, 2024

Closing as documented and planned behavior exhibited here.

from rcpp.

Related Issues (20)

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.