From p.dalgaard at biostat.ku.dk  Wed Sep 24 07:54:11 2008
From: p.dalgaard at biostat.ku.dk (Peter Dalgaard)
Date: Wed, 24 Sep 2008 07:54:11 +0200
Subject: [Rd] function can permanently modify calling function
	via	substitute?
In-Reply-To: <34988bf10809232150g65e3aba3l9ddffae0d6b2c70b@mail.gmail.com>
References: <34988bf10809232150g65e3aba3l9ddffae0d6b2c70b@mail.gmail.com>
Message-ID: <48D9D603.4080101@biostat.ku.dk>

Perry de Valpine wrote:
> Dear R-devel:
>
> The following code seems to allow one function to permanently modify a
> calling function.  I did not expect this would be allowed (short of
> more creative gymnastics) and wonder if it is really intended.  (I can
> see other ways to accomplish the intended task of this code [e.g. via
> match.call instead of substitute below] that do not trigger the
> problem, but I don't think that is the point.)
>
> do.nothing <- function(blah) {force(blah)}
>
> do.stuff.with.call <- function(mycall) {
>   raw.mycall <- substitute(mycall);   # expected raw.mycall would be local
>   print( sys.call() )
>
>   # do.nothing( raw.mycall );  # See below re: commented lines.
>   # .Call( "showNAMED", raw.mycall[[2]] )
>
>   force( mycall );  # not relevant where (or whether) this is done
>   raw.mycall[[2]] <- runif(1); # permanently modifies try.me on the
> first time only
>
>   # .Call( "showNAMED", raw.mycall[[2]] )
>
>   raw.mycall
> }
>
> gumbo <- function(x) {
>   writeLines( paste( "gumbo : x =" ,  x ) )
>   return(x);
> }
>
> try.me <- function() {
>   one.val <- 111;
>   one.ans <- do.stuff.with.call( mycall = gumbo( x = one.val ) );
>   one.ans
> }
>
> # after source()ing the above:
>   
>> deparse(try.me)
>>     
> [1] "function () "
> [2] "{"
> [3] "    one.val <- 111"
> [4] "    one.ans <- do.stuff.with.call(mycall = gumbo(x = one.val))"
> [5] "    one.ans"
> [6] "}"
>   
>> try.me()
>>     
> do.stuff.with.call(mycall = gumbo(x = one.val))
> gumbo : x = 0.396524668671191
> gumbo(x = 0.396524668671191)
>   
>> deparse(try.me)
>>     
> [1] "function () "
> [2] "{"
> [3] "    one.val <- 111"
> [4] "    one.ans <- do.stuff.with.call(mycall = gumbo(x = 0.396524668671191))"
> [5] "    one.ans"
> [6] "}"
>   
>> try.me()
>>     
> do.stuff.with.call(mycall = gumbo(x = 0.396524668671191))
> gumbo : x = 0.396524668671191
> gumbo(x = 0.0078618151601404)
>   
>> deparse(try.me)
>>     
> [1] "function () "
> [2] "{"
> [3] "    one.val <- 111"
> [4] "    one.ans <- do.stuff.with.call(mycall = gumbo(x = 0.396524668671191))"
> [5] "    one.ans"
> [6] "}"
>
> So, after the first call of try.me(), do.stuff.with.call has
> permanently replaced the name one.val in line 2 of try.me with a
> numeric (0.396...).  Subsequent calls from try.me to
> do.stuff.with.call now reflect that change, but do.stuff.with.call
> does not modify the try.me object again. (Note this means one needs to
> keep reloading try.me to investigate).
>
> If this is a problem worth investigating, here are a couple of other
> observations that may be relevant but are obviously speculative.
>
> 1. If the third line of do.stuff.with.call is uncommented (and try.me
> also reloaded), the unexpected behavior does not occur.  Since
> do.nothing is eponymous, I was surprised because I believed it should
> not impact any other behavior.  Speculating with limited knowledge, I
> thought this might implicate something that is supposed to stay
> under-the-hood, such as the "`call by value' illusion" described in
> the "R internals" documentation.
>
> 2. Poking slightly further, I looked at the NAMED values using this C
> code via R CMD SHLIB and dyn.load:
> #include "R.h"
> #include "Rdefines.h"
> SEXP showNAMED(SEXP obj) {
>   Rprintf("%i\n", NAMED(obj));
>   return(R_NilValue);
> }
> Uncommenting the .Call lines in do.stuff.with.call (with the
> do.nothing line re-commented) reveals that on the first time
> do.stuff.with.call is called from try.me, raw.mycall[[2]] has NAMED ==
> 1 both before and after the `[[<-` line.  On subsequent calls it has
> NAMED == 2 before and NAMED == 1 after.  If I follow how NAMED is
> used, this seems relevant.
>
>   
Yes and no. This does sound like a bug and NAMED is likely involved, but 
I don't think raw.mycall[[2]] is the thing to look at. More likely, the 
issue is that raw.mycall[ itself has NAMED == 1 because otherwise [[<- 
assignment would duplicate it first. This suggests that substitute has 
the bug.

 

-- 
   O__  ---- Peter Dalgaard             ?ster Farimagsgade 5, Entr.B
  c/ /'_ --- Dept. of Biostatistics     PO Box 2099, 1014 Cph. K
 (*) \(*) -- University of Copenhagen   Denmark      Ph:  (+45) 35327918
~~~~~~~~~~ - (p.dalgaard at biostat.ku.dk)              FAX: (+45) 35327907



[Rd] function can permanently modify calling function via substitute?
Peter Dalgaard