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@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-tier...@uiowa.edu
Iowa City, IA 52242                 WWW:  http://www.stat.uiowa.edu

______________________________________________
R-devel@r-project.org mailing list
https://stat.ethz.ch/mailman/listinfo/r-devel

Reply via email to