1

Consider the example below:

> x=2
> myfun = function(y) x*y
> myfun(3)
[1] 6
> x=4
> myfun(3)
[1] 12

How would I have to define myfun so that its definition keeps the value of x such as it is at the time of definition, rather than a reference to x? (i.e., that the second call myfun(3) also yields 6 rather than 12).

EDIT: changed the title to remove incorrect terminology.

mitchus
  • 4,677
  • 3
  • 35
  • 70
  • 2
    This is possible, but a little bit odd. Can you explain why you want to do this? In any case, your title is misleading (or perhaps wrong). Your function is looking up the `value` in the chain of environments. Nothing is being referenced here. – Andrie Aug 07 '12 at 12:21
  • I agree with @Andrie that it's hard to conceive of a use case for this. Perhaps what you want is a closure? – Ari B. Friedman Aug 07 '12 at 12:35
  • It is possible that my terminology is incorrect. What I mean by reference is that the body of the function contains "x" rather than the value held by x at the time of definition (2). I would like the body to not contain "x", i.e. to take a snapshot. Why do you think this is odd? – mitchus Aug 07 '12 at 12:35
  • @AriB.Friedman Closures can definitely do this. I may modify my answer to reflect this. – Andrie Aug 07 '12 at 12:38
  • @mitchus It's a little bit odd because usually if you want to take a snapshot of a variable value, you'll do that in the code. – Andrie Aug 07 '12 at 12:40
  • @Andrie What if I want to pass `myfun` as an argument to another function? In another scope, `myfun` may no longer have access to `x`, or `x` may refer to something different. In any case, what would you suggest I change the title to? – mitchus Aug 07 '12 at 12:48
  • Please expand on your question. Perhaps give a bit of a flavour of the problem you are trying to solve. At the moment I still don't understand what you're trying to do, so can't help. What is your use case? If you want to save the value of a variable as a snapshot, why can't you simply do that in the code? – Andrie Aug 07 '12 at 12:51
  • @mitchus That's exactly the problem with using global variables. Please see http://stackoverflow.com/questions/5526322/examples-of-the-perils-of-globals-in-r-and-stata and http://stackoverflow.com/questions/9851655/why-is-using-frowned-upon-and-how-can-i-avoid-it , and strongly consider Andrie's suggestion to pass x as a function argument, with a default value if necessary. As an aside, you are neither passing by value nor by reference here--you're not passing at all! So your title is not quite accurate. – Ari B. Friedman Aug 07 '12 at 13:02

4 Answers4

4

I have to guess a little bit what your purpose is. Perhaps you simply need to define one of your arguments with a default value:

myfun <- function(y, x=2){
  x * y
}

Then use it:

x <- 3

myfun(4)
[1] 8

myfun(x=4, 3)
[1] 12

myfun(x)
[1] 6

But perhaps you really are describing a closure.

An object is data with functions. A closure is a function with data.

--- John D Cook

Here is an example. First define a closure that remembers a snapshot:

newSnapshot <- function(x){
  xx <- x
  function(y) xx * y
}

Then use it:

x <- 10
myfun <- newSnapshot(x)

myfun(4)
[1] 40

x <- 4
myfun(5)
[1] 50
Community
  • 1
  • 1
Andrie
  • 176,377
  • 47
  • 447
  • 496
3

Almost the same question was asked on the R-help mailing list yesterday. See the discussion on Nabble for the various ways you can do that.

http://r.789695.n4.nabble.com/Force-evaluation-of-a-symbol-when-a-function-is-created-td4639350.html

And here are three ways to do it (gathered from the R-help discussion):

x <- 2

f1 <- local({x.now <- x;function(y) x.now*y})
f2 <- evalq(function(y)a*y,env=list(a=x))

multiply_by_x <- function(x) {
    force(x)
    function(y) y*x
}

f3 <- multiply_by_x(x)

with results

> f1(3)
[1] 6
> f2(3)
[1] 6
> f3(3)
[1] 6

> x <- 4
> f1(3)
[1] 6
> f2(3)
[1] 6
> f3(3)
[1] 6
Bhas
  • 1,844
  • 1
  • 11
  • 9
  • This is exactly what I was looking for. Incidentally, in the meantime I found a fourth way which may be a bit hacky: `body(myfun) = eval(expression(parse(text = paste(x, "*y"))))` – mitchus Aug 07 '12 at 13:15
  • 2
    I suggest you look at `require(fortunes); fortune(106)` before you consider the use of `parse()` again. :-) – Gavin Simpson Aug 07 '12 at 13:28
  • A bit less horrible: `formals(myfun)$x=x` – mitchus Sep 04 '12 at 07:15
2

One approach is this:

myfun <- function(x = 2) {
    function(y) {
        x * y
    }
}

Basically we write a function that returns a function that does the computation we want. In the above x is set to 2 by default but you can vary this when you call myfun. When we call myfun() we save the returned function, in foo in the example below:

> foo <- myfun()

Now, no matter what you do to x in the global environment foo() will always use the value of x that was defined in the environment of myfun() when that function was called.

> foo(3)
[1] 6
> x <- 6
> foo(3)
[1] 6
> x <- 4
> foo(3)
[1] 6

This all works because the environment of the function created by the call to myfun() contains x and that x has the value of x that was present when the function was defined.

> environment(foo)$x
[1] 2
Gavin Simpson
  • 170,508
  • 25
  • 396
  • 453
  • thanks for the reply. The thing is, at the time of writing the code I don't know the value `x` will have at the time of defining `myfun` (unlike what my poorly chosen example implies). – mitchus Aug 07 '12 at 13:18
2

Here's another closure solution:

myfun <- local({
  x <- 2
  list(
    f=function(y) {
      x*y
    },
    set.x=function(newx) {
      x <<- newx
    },
    get.x=function() {
      x
    }
  )
})

Then you can use it as follows:

> myfun$get.x()
[1] 2
> myfun$set.x(5)
> myfun$get.x()
[1] 5
> myfun$f(3)
[1] 15
Ari B. Friedman
  • 71,271
  • 35
  • 175
  • 235