Daniel Daniel - 1 year ago 106
R Question

Inconsistent results in R using .Call inside lapply

I've created a package using the Rcpp package's

function containing one .cpp file with a C++ function returning 0:

#include <Rcpp.h>

using namespace Rcpp;

// [[Rcpp::export]]
RcppExport SEXP just_zero() {
Rcpp::RNGScope __rngScope;
return wrap(0.0);

When I install and load the package from R I can call the function with .Call via lapply. As expected, it (appears to) always return 0:

> x <- lapply(seq(10000), function(i) { x <- .Call('just_zero'); stopifnot(x == 0); x } )
#*no errors!*

However, apparently the value which is returned by
contains non-zeros:

> range(simplify2array(x))
[1] 0 3

Unfortunately, using
doesn't make these returned values reproducible, and sometimes I do get
[1] 0 0
, sometimes other values, e.g.
[1] "0" "TRUE"
. An additional clue is that removing the line
Rcpp::RNGScope __rngScope;
fixes the problem.

Why are there non-zero elements in the object returned by
(particularly as we've checked the values returned by
), and how come using
is causing it?

I've reproduced this behaviour on Linux and OS X. Session info from OS X pasted below:

> sessionInfo()
R Under development (unstable) (2016-08-03 r71023)
Platform: x86_64-apple-darwin13.4.0 (64-bit)
Running under: OS X Mavericks 10.9.5

[1] en_GB.UTF-8/en_GB.UTF-8/en_GB.UTF-8/C/en_GB.UTF-8/en_GB.UTF-8

attached base packages:
[1] stats graphics grDevices utils datasets methods base

other attached packages:
[1] bug_1.0 devtools_1.12.0

loaded via a namespace (and not attached):
[1] tools_3.4.0 withr_1.0.2 memoise_1.0.0 Rcpp_0.12.6 git2r_0.15.0
[6] digest_0.6.10

Answer Source

Here's an example that reproduces the issue consistently for me.

#include <Rcpp.h>
using namespace Rcpp;

// [[Rcpp::export]]
void dummy() {}

extern "C" SEXP just_zero() {
  Rcpp::RNGScope rngScope;
  return wrap(0.0);

/*** R
n <- 1E5
x <- unlist(lapply(seq(n), function(i) {


Calling Rcpp::sourceCpp() on this gives me e.g.

> unique(x)
 [1]     0  8371 16021 20573 25109 43103 47563 56438 60852 78413 82773 95765

What's causing this issue? To understand this, we need to understand the definition of RNGScope: we can see it here:


and the methods it uses are defined here:


with the most important function, PutRNGState, being defined here:


Now, this is effectively what happens when just_zero is called:

  1. RNGScope object is created, with its associated destructor primed to run.
  2. The result of wrap(0.0), being a REALSXP with length 1 and value 0, is created. Note that this object is unprotected and so is eligible for garbage collection.
  3. The function returns, and the RNGScope destructor is called.
  4. This calls the R routine PutRNGstate(), which itself will call allocVector, thereby triggering the garbage collector. This implies the SEXP object you wanted to return can be collected, and hence will be garbage!

So, in sum -- use Rcpp attributes, as it will take care of doing this all safely for you.

To understand why Rcpp attributes makes this 'safe', look at the generated code:

// just_zero
SEXP just_zero();
RcppExport SEXP sourceCpp_0_just_zero() {
    Rcpp::RObject __result;
    Rcpp::RNGScope __rngScope;
    __result = Rcpp::wrap(just_zero());
    return __result;

Note that the output result is assigned to Rcpp::RObject, which protects the object, and we ensure that this object is constructed before the RNGScope object, which ensures it will remain protected while the RNGScope destructor is run.

Recommended from our users: Dynamic Network Monitoring from WhatsUp Gold from IPSwitch. Free Download