Skip to content

'deparse(substitute'))' then 'assign' in a S4 methods

4 messages · William Dunlap, Christophe Genolini

#
Hi the list,

I am writing a function in which I need to affect a variable on a higher
level. My fnction could be:

++++++++++++++++++
fooBis <- function(x){
      nameObject <- deparse(substitute(x))
      print(nameObject)
      assign(nameObject,4,envir=parent.frame())
}
[1] "e"
[1] 4
-----------------

(to simplify, this fnction can affect only the number 4. But it does it in
the parent frame).

My problem is that I use S4 programming. So the code becomes:

+++++++++++++
setGeneric("foo",function(x){standardGeneric("foo")})
setMethod("foo","ANY",
    function(x){
      nameObject <- deparse(substitute(x))
      print(nameObject)
      assign(nameObject,4,envir=parent.frame())
   }
)
-----------
But it does not work since the definition of foo is now:

+++++++++
nonstandardGenericFunction for "foo" defined from package ".GlobalEnv"
function (x) 
{
    standardGeneric("foo")
}
<environment: 0x125b7c0c>
-----------------
So how can I solve this problem? Is it possible to assign a value to a
variable on the upper level using S4?

Sincerely
Christophe


--
View this message in context: http://r.789695.n4.nabble.com/deparse-substitute-then-assign-in-a-S4-methods-tp4356748p4356748.html
Sent from the R help mailing list archive at Nabble.com.
#
Using substitute() and assign(..., envir=parent.frame()) in
fooBis will lead you into a lot of trouble.  It is nicer to
use a 'replacement function', whose  name ends with '<-',
whose last argument is named 'value', and which returns
the modified first argument.  They are usually paired with
extractor functions.

E.g.,

 > twice <- function(x, value) { 2*x } # 'extractor function'
 > `twice<-` <- function(x, value) { x <- value/2 ; x } # 'replacement function'
 > x <- 1:5
 > twice(x)
 [1]  2  4  6  8 10
 > twice(x)[2] <- 100
 > x
 [1]  1 50  3  4  5

Your example, setting the input to a fixed value, could be
 `fooBis<-` <- function(x, value) { x <- 4 ; x }
You would have to call it as an assignment: whatever is on
the right side would be ignored
 x <- 20
 fooBis(x) <- NULL
 # x should be 4 now

There should not be any problem turning these into S4 generics
in the usual way.


Bill Dunlap
Spotfire, TIBCO Software
wdunlap tibco.com
1 day later
#
Thanks Bill,

In France, there is a famous joke about politician: "Tell me what you need,
I will explain you how to do without"... But in my specific case, I can not
use the classical <- and [, it is why I ask my question.

More precisely, my fonction fooBis can be very long to end. So I want to
update the value of my variable from time to time. 
'assign' + break will work, whereas `fooBis<-` <- function(x, value) { x <-
4 ; for(i in 1:10000000){};x }  + break will not work.

Christophe

--
View this message in context: http://r.789695.n4.nabble.com/deparse-substitute-then-assign-in-a-S4-methods-tp4356748p4361210.html
Sent from the R help mailing list archive at Nabble.com.
#
The interrupt issue is somewhat orthogonal to the SV4/scoping issue
you asked about.  Trying to put things in the callers frame is
very tricky.  E.g., SV4 methods can insert new frames between
your code and the caller.  Perhaps you could try the following
sort of construct, in which your desired function is inside a
wrapper, whose only job is to collect results from the inner function.
Then make the outer function your SV4 method.

f <- function (n) {
    retval <- NULL # just a placeholder so <<- from f_inner lands here
    f_inner <- function(n) {
        on.exit({
            retval <<- retval_inner # or could use assign(env=parent.env(), ...)
            message("stashed retval_inner as retval")
        })
        retval_inner <- 100
        tryCatch(
            expr = for (i in seq_len(n)) {
                       Sys.sleep(1)
                       retval_inner <- retval_inner + 1
                   },
            interrupt = function(...) message("interrupted in iteration ", i))
    }
    f_inner(n)
    retval
}

E.g.,

  > r <- f(5)
  stashed retval_inner as retval
  > r
  [1] 105
  > rm(r)
  > r <- f(50) # hit interrupt key after a few seconds
  interrupted in iteration 4
  stashed retval_inner as retval
  > r
  [1] 103
  > sapply( 5:1, f) # hit interrupt key sporadically
  stashed retval_inner as retval
  interrupted in iteration 2
  stashed retval_inner as retval
  interrupted in iteration 3
  stashed retval_inner as retval
  interrupted in iteration 2
  stashed retval_inner as retval
  stashed retval_inner as retval
  [1] 105 101 102 101 101

Bill Dunlap
Spotfire, TIBCO Software
wdunlap tibco.com