[Rcpp-devel] RCPP_USE_UNWIND_PROTECT by default
Dirk Eddelbuettel
edd at debian.org
Sun Feb 6 17:56:33 CET 2022
On 6 February 2022 at 17:40, Jeroen Ooms wrote:
| We can try to take V8 out of the equation, and see what actually
| causes the change. V8 uses (and tests!) the Rcpp feature to call an R
| function from C++. This behaves quite differently when using
| RCPP_UNWIND_PROTECT.
|
| Here is a dummy package to demonstrate this: https://github.com/jeroen/uptest
|
| The use case is simple: we want to call some R function from C++, and
| if it fails, catch the error message and deal with it in C++. I
| suspect there are more packages doing this, but perhaps they are not
| testing this case.
|
| The example from uptest above show that when we compile with
| RCPP_UNWIND_PROTECT, any R error is always printed directly to the
| console. Even if we catch the Rcpp::LongjumpException in C++, the R
| error still seems to bubble up (as Iñaki also noted). I think this is
| at least surprising.
|
| Then I am not sure what we do in C++ now with this
| Rcpp::LongjumpException if we catch it. We certainly don't want to
| unwind all the way in the middle of running the javascript code. The
| JavaScript code should be able to catch the R error, and continue
| running the script.
|
| Anyway if you want to make RCPP_UNWIND_PROTECT the default, I can
| obviously opt-out in V8, but as an Rcpp user I am not convinced this
| is an improvement.
Thanks for the feedback. I think there is an easy-to-understand, easy-to-make
error in a sample package (but kudos for creating one!). Because Rcpp will
always wrap try/catch around the function you create with its mechanism, the
layer inside is redundant. So I suggest the C++ function file becomes this
simpler / shorter variant:
#include <Rcpp.h>
using namespace Rcpp;
// [[Rcpp::export]]
Rcpp::NumericVector call_r_from_rcpp() {
Rcpp::Function callback = Rcpp::Environment::namespace_env("uptest")["callback"];
callback();
return Rcpp::NumericVector::create(42);
}
which behaves fine for me in both cases.
First, "as I found the repo" so with the new RCPP_UNWIND_PROTECT added:
edd at rob:/tmp/uptest(master)$ install.r . # the usual wrapper from littler
* installing *source* package ‘uptest’ ...
** using staged installation
** libs
rm -f uptest.so RcppExports.o callback.o
ccache g++-11 -I"/usr/share/R/include" -DNDEBUG -DRCPP_USE_UNWIND_PROTECT -I'/usr/local/lib/R/site-library/Rcpp/include' -fpic -g -O3 -Wall -pipe -pedantic -c RcppExports.cpp -o RcppExports.o
ccache g++-11 -I"/usr/share/R/include" -DNDEBUG -DRCPP_USE_UNWIND_PROTECT -I'/usr/local/lib/R/site-library/Rcpp/include' -fpic -g -O3 -Wall -pipe -pedantic -c callback.cpp -o callback.o
ccache g++-11 -Wl,-S -shared -L/usr/lib/R/lib -Wl,-Bsymbolic-functions -flto=auto -Wl,-z,relro -o uptest.so RcppExports.o callback.o -L/usr/lib/R/lib -lR
installing to /usr/local/lib/R/site-library/00LOCK-uptest/00new/uptest/libs
** R
** byte-compile and prepare package for lazy loading
** help
*** installing help indices
** building package indices
** testing if installed package can be loaded from temporary location
** checking absolute paths in shared objects and dynamic libraries
** testing if installed package can be loaded from final location
** testing if installed package keeps a record of temporary installation path
* DONE (uptest)
edd at rob:/tmp/uptest(master)$ R -q
> library(uptest)
> uptest()
Error in (function () : Ouch from R
> qn
edd at rob:/tmp/uptest(master)$
Second, after editing src/Makevars and removing of object files:
edd at rob:/tmp/uptest(master)$ be src/Makevars # an alias for emacsclient inside byobu
edd at rob:/tmp/uptest(master)$ rm src/*.o src/*.so
edd at rob:/tmp/uptest(master)$ install.r .
* installing *source* package ‘uptest’ ...
** using staged installation
** libs
rm -f uptest.so RcppExports.o callback.o
ccache g++-11 -I"/usr/share/R/include" -DNDEBUG -I'/usr/local/lib/R/site-library/Rcpp/include' -fpic -g -O3 -Wall -pipe -pedantic -c RcppExports.cpp -o RcppExports.o
ccache g++-11 -I"/usr/share/R/include" -DNDEBUG -I'/usr/local/lib/R/site-library/Rcpp/include' -fpic -g -O3 -Wall -pipe -pedantic -c callback.cpp -o callback.o
ccache g++-11 -Wl,-S -shared -L/usr/lib/R/lib -Wl,-Bsymbolic-functions -flto=auto -Wl,-z,relro -o uptest.so RcppExports.o callback.o -L/usr/lib/R/lib -lR
installing to /usr/local/lib/R/site-library/00LOCK-uptest/00new/uptest/libs
** R
** byte-compile and prepare package for lazy loading
** help
*** installing help indices
** building package indices
** testing if installed package can be loaded from temporary location
** checking absolute paths in shared objects and dynamic libraries
** testing if installed package can be loaded from final location
** testing if installed package keeps a record of temporary installation path
* DONE (uptest)
edd at rob:/tmp/uptest(master)$ R -q
> library(uptest)
> uptest()
Error in call_r_from_rcpp() : Evaluation error: Ouch from R.
> qn
edd at rob:/tmp/uptest(master)$
So in short
Rcpp on CRAN: Error in call_r_from_rcpp() : Evaluation error: Ouch from R.
Rcpp proposed: Error in (function () : Ouch from R
which thanks to the hard work by Lionel a while back is both faster and nicer.
It's Sunday and I only had one pot of coffee so far so it is plausible and
possible I omitted something, but it looks like this is actually net better.
Cheers, Dirk
--
https://dirk.eddelbuettel.com | @eddelbuettel | edd at debian.org
More information about the Rcpp-devel
mailing list