[Rd] unset() function?

luke-tierney at uiowa.edu luke-tierney at uiowa.edu
Sat Aug 22 16:50:47 CEST 2015


This wouldn't actually work at present as evaluating a promise always
sets NAMED to 2. With reference counting it would work so might be
worth considering when we switch.

Going forward it would be best to use MAYBE_REFERENCED to test whether
a duplicate is needed -- this macro is defined appropriately whether R
is compiled to use NAMED or reference counting.

Best,

luke

On Fri, 21 Aug 2015, William Dunlap 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]]
>
> ______________________________________________
> R-devel at r-project.org mailing list
> https://stat.ethz.ch/mailman/listinfo/r-devel
>

-- 
Luke Tierney
Ralph E. Wareham Professor of Mathematical Sciences
University of Iowa                  Phone:             319-335-3386
Department of Statistics and        Fax:               319-335-3017
    Actuarial Science
241 Schaeffer Hall                  email:   luke-tierney at uiowa.edu
Iowa City, IA 52242                 WWW:  http://www.stat.uiowa.edu



More information about the R-devel mailing list