9

I'm new to R (and programming generally), and confused about why the following bits of code yield different results:

x <- 100

for(i in 1:5){
  x <- x + 1
  print(x)
}

This incrementally prints the sequence 101:105 as I would expect.

x <- 100

f <- function(){
  x <- x + 1
  print(x)
}

for(i in 1:5){
  f()
}

But this just prints 101 five times.

Why does packaging the logic into a function cause it to revert to the original value on each iteration rather than incrementing? And what can I do to make this work as a repeatedly-called function?

2 Answers 2

16

The problem

It is because in your function you are dealing with a local variable x on the left side, and a global variable x on the right side. You are not updating the global x in the function, but assigning the value of 101 to the local x. Each time you call the function, the same thing happens, so you assign local x to be 101 5 times, and print it out 5 times.

To help visualize:

# this is the "global" scope
x <- 100

f <- function(){
  # Get the "global" x which has value 100,
  # add 1 to it, and store it in a new variable x.
  x <- x + 1
  # The new x has a value of 101
  print(x)
}

This would be similar to the following code:

y <- 100

f <- function(){
  x <- y + 1
  print(x)
}

One possible fix

As for what to do to fix it. Take the variable as the argument, and pass it back as the update. Something like this:

f <- function(old.x) {
    new.x <- old.x + 1
    print(new.x)
    return(new.x)
}

You would want to store the return value, so your updated code would look like:

x <- 100

f <- function(old.x) {
    new.x <- old.x + 1
    print(new.x)
    return(new.x)
}

for (i in 1:5) {
  x <- f(x)
}
Sign up to request clarification or add additional context in comments.

Comments

2

This does what you want:

f <- function(){
  x <<- x + 1
  print(x)
}

But you shouldn't do this. Globals are not a good construct. Functions with side-effects cause code to be hard to understand and hard to debug.

A safer way to use a global is to encapsulate it into another environment. Here is an example:

create.f <- function(x) {
  return(function() {
    x <<- x + 1
    print(x)
  })
}

f <- create.f(100)
for (i in 1:5) f()
## [1] 101
## [1] 102
## [1] 103
## [1] 104
## [1] 105

Here, the "global" x is in the environment of the body of create.f, where f is defined, and not the global environment. The environment of a function is the environment in which it is defined (and not that in which it is called).

1 Comment

It might solve your problem now, but please avoid using global variables and do not get too comfortable with them. For small scripts, using a global is probably not that bad, but small scripts get big and then these things can really bite you.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.