[Rd] unset() function?
William Dunlap
wdunlap at tibco.com
Fri Aug 21 23:12:50 CEST 2015
> Does R have a function like the S/S++ unset() function?
That should be 'S+' or 'S-Plus', not the typo 'S++'.
Bill Dunlap
TIBCO Software
wdunlap tibco.com
On Fri, Aug 21, 2015 at 1:43 PM, William Dunlap <wdunlap at tibco.com> wrote:
> Does R have a function like the S/S++ unset() function?
> unset(name) would remove 'name' from the current evaluation
> frame and return its value. It allowed you to safely avoid
> some memory copying when calling .C or .Call.
>
> E.g., suppose you had C code like
> #include <R.h>
> #include <Rinternals.h>
> SEXP add1(SEXP pX)
> {
> int nProtected = 0;
> int n = Rf_length(pX);
> int i;
> double* x;
> Rprintf("NAMED(pX)=%d: ", NAMED(pX));
> if (NAMED(pX)) {
> Rprintf("Copying pX before adding 1\n");
> PROTECT(pX = duplicate(pX)); nProtected++;
> } else {
> Rprintf("Changing pX in place\n");
> }
> x = REAL(pX);
> for(i=0 ; i<n ; i++) {
> x[i] = x[i] + 1.0;
> }
> UNPROTECT(nProtected);
> return pX;
> }
>
> If I call this from an R function
> add1 <- function(x) {
> stopifnot(inherits(x, "numeric"))
> .Call("add1", x)
> }
> it will will always copy 'x', even though not copying would
> be safe (since add1 doesn't use 'x' after calling .Call()).
> > add1(c(1.2, 3.4))
> NAMED(pX)=2: Copying pX before adding 1
> [1] 2.2 4.4
> If I make the .Call directly, without a nice R function around it
> then I can avoid the copy
> > .Call("add1", c(1.2, 3.4))
> NAMED(pX)=0: Changing pX in place
> [1] 2.2 4.4
>
> If something like S's unset() were available I could avoid the copy,
> when safe to do so, by making the .Call in add1
> .Call("add1", unset(x))
>
> If you called this new add1 with a named variable from another
> function the copying would be done, since NAMED(x) would be
> 2 even after the local binding was removed. It actually requires some
> care to to eliminate the copying, as all the functions in the call
> chain would have to use unset() when possible.
>
> I ask this because I ran across a function in the 'bit' package that
> does not have its C code call duplicate but instead assumes the
> x[1] <- x[1] will force x to be copied:
> "!.bit" <- function(x){
> if (length(x)){
> ret <- x
> ret[1] <- ret[1] # force duplication
> .Call("R_bit_not", ret, PACKAGE="bit")
> }else{
> x
> }
> }
> If you optimize things so that 'ret[1] <- ret[1]' does not copy 'ret',
> then this function alters its input. It a function like unset()
> were there then the .Call could be
> .Call("R_bit_not", unset(x))
>
> I suppose the compiler could analyze the code and see that
> x was not used after the .Call and thus feel free to avoid the
> copy.
>
> In any case bit's maintainer should add something like
> if(NAMED(x) {
> PROTECT(x=duplicate(x));
> nProtect++;
> }
> ...
> UNPROTECT(nProtect);
> in the C code, but unset() would help avoid unneeded duplications.
>
>
> Bill Dunlap
> TIBCO Software
> wdunlap tibco.com
>
[[alternative HTML version deleted]]
More information about the R-devel
mailing list