4

Actual question

Could someone get me started on what I need to do to implement the code of unlockEnvironment below in Rcpp?

Background

Came across this post and tried Winston Chang's solution based on C code with inline. It works, but I have the feeling I know too little (practically nothing, that is) about either inline or C/C++ to really know what I'm doing ;-)

So I thought this would be a great opportunity to finally start learning on how to use R as an interface to C and C++. And I think I'd like to hopp on the Rcpp train for doing so!

The code from Winston's Gist

require("inline")

inc <- '
/* This is taken from envir.c in the R 2.15.1 source
https://github.com/SurajGupta/r-source/blob/master/src/main/envir.c
*/
#define FRAME_LOCK_MASK (1<<14)
#define FRAME_IS_LOCKED(e) (ENVFLAGS(e) & FRAME_LOCK_MASK)
#define UNLOCK_FRAME(e) SET_ENVFLAGS(e, ENVFLAGS(e) & (~ FRAME_LOCK_MASK))
'
src <- '
if (TYPEOF(env) == NILSXP)
error("use of NULL environment is defunct");
if (TYPEOF(env) != ENVSXP)
error("not an environment");

UNLOCK_FRAME(env);

// Return TRUE if unlocked; FALSE otherwise
SEXP result = PROTECT( Rf_allocVector(LGLSXP, 1) );
LOGICAL(result)[0] = FRAME_IS_LOCKED(env) == 0;
UNPROTECT(1);

return result;
'
unlockEnvironment <- inline::cfunction(
  signature(env = "environment"),
  includes = inc,
  body = src
)

Refactoring error

On a side note: I ran into an error with Winston's code when I organize it in a certain way in the /R directory of my package project:

Using S4 methods most of the time, I tried to factor Winston's code out into a standard R function .unlockEnvironment() that I put into the file /R/.unlockEnvironment.r

I then would create my S4 methods for unlockEnvironment() in /R/unlockEnvironment.r. The method with signature env:environment would then simply call .unlockEnvironment(env = env).

Setting up things that way, I end up with the following error:

Error in .Primitive(".Call")(, env) : NULL value passed as symbol address

If I put the code in /R/.unlockEnvironment.r directory with in the respective method in /R/unlockEnvironment.r (thus re-sourcing the inline code each time the respective method of unlockEnvironment() is called), everything works just fine - but it's very inefficient because of the repeated re-sourcing.

So I guess this must have either something to do with the way the C code is written or with the way you need to organize your C-based functions when using inline?

Community
  • 1
  • 1
Rappster
  • 12,762
  • 7
  • 71
  • 120
  • I do not understand what you want from Rcpp here. R has a C API, and Winston's code uses it. We can write the same code to be called from Rcpp via Rcpp Attributes but it _remains of course C code talking to the same C API_. Whether or not that works for you has more to do the with C API and what you can or cannot do with environment -- rather than whether or you not involve Rcpp to build it. So not an Rcpp question AFAICT. – Dirk Eddelbuettel Sep 18 '14 at 13:46
  • It's not that I want to get *rid* of the C-code, quite the opposite! I just thought this would maybe be an "easy enough for me to grasp" example to see how the same thing is done by using `Rcpp` instead of `inline` as I want to learn how to use R as an interface to C++. I'm indifferent with respect to the code either remaining C-code or it being translated to C++ code. Sorry if this seems like a stupid noob question, but I don't know my way around C/C++ yet ;-) – Rappster Sep 18 '14 at 14:14

1 Answers1

8

It sounds like your question basically amounts to, 'how do I use Rcpp::attributes'? And I would suggest that you go over many of the examples in the Rcpp Gallery to learn a bit more.

The main idea: write some C++ code, put it a .cpp file, then call Rcpp::sourceCpp(<file>) to load it. For this particular example:

#include <Rcpp.h>
using namespace Rcpp;

/* This is taken from envir.c in the R 2.15.1 source
https://github.com/SurajGupta/r-source/blob/master/src/main/envir.c
*/
#define FRAME_LOCK_MASK (1<<14)
#define FRAME_IS_LOCKED(e) (ENVFLAGS(e) & FRAME_LOCK_MASK)
#define UNLOCK_FRAME(e) SET_ENVFLAGS(e, ENVFLAGS(e) & (~ FRAME_LOCK_MASK))

// [[Rcpp::export]]
bool unlock_environment(Environment env) {
  UNLOCK_FRAME(env);
  return FRAME_IS_LOCKED(env) == 0;
}

/*** R
env <- new.env()
lockEnvironment(env)
try(env$a <- 1) ## error
unlock_environment(env)
env$a <- 1
*/

Calling Rcpp::sourceCpp() on a file with these contents gives me:

> Rcpp::sourceCpp('~/scratch/unlock.cpp')

> env <- new.env()

> lockEnvironment(env)

> try(env$a <- 1) ## error
Error in env$a <- 1 : cannot add bindings to a locked environment

> unlock_environment(env)
[1] TRUE

> env$a <- 1 ## success!

The main little features here:

  1. You can provide signatures using base / STL C++ types, or Rcpp types as well. Note that bool is the C++ bool type, and Environment is an Rcpp type encompassing environments.
  2. Rcpp Attributes handles automatic conversion of these C++ return types to R's SEXP.

You might like Hadley's adv-r introduction as well.

Kevin Ushey
  • 20,530
  • 5
  • 56
  • 88
  • 1
    Nice post. The Rcpp Gallery, and Hadley's site are fine suggestion but there is actually a [vignette about Rcpp Attributes](http://cran.rstudio.com/web/packages/Rcpp/vignettes/Rcpp-attributes.pdf) as well. – Dirk Eddelbuettel Sep 19 '14 at 01:28