From wdunlap at tibco.com  Fri Aug 21 23:12:50 2015
From: wdunlap at tibco.com (William Dunlap)
Date: Fri, 21 Aug 2015 14:12:50 -0700
Subject: [Rd] unset() function?
In-Reply-To: <CAF8bMcZEegtke2bCOb96+xZGTaCSOamEMba-cU-i03Dj7jCnxA@mail.gmail.com>
References: <CAF8bMcZEegtke2bCOb96+xZGTaCSOamEMba-cU-i03Dj7jCnxA@mail.gmail.com>
Message-ID: <CAF8bMcZGThqj3pzrOBNTwvPfjuGifEW2C6p3X5duQx24OwKtBA@mail.gmail.com>

> 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]]



[Rd] unset() function?
William Dunlap