2

How do i modify the value of vairable 'loco' in following snippet:

poco <- function() {

func <- function(x) {
    print(loco)
    loco <- loco+x
}

loco <- 123
func(1)
func(2)
}

this functions gives following result:

> poco()
[1] 123
[1] 123
smci
  • 32,567
  • 20
  • 113
  • 146
FUD
  • 5,114
  • 7
  • 39
  • 61
  • 2
    what is your expected output? using `loco <<- loco + x` may do what you're looking for. – Justin Oct 09 '12 at 15:19
  • 1
    @I'm guessing Justin's comment is what you're looking for but really that isn't a good route to go in R. – Dason Oct 09 '12 at 15:20
  • 1
    Pass loco to `func` and let `func` return it. – Roland Oct 09 '12 at 15:20
  • @Justin nice, please post this as an answer and a little explaination would be great :) – FUD Oct 09 '12 at 15:24
  • @FUD, this might solve your immediate problem, but once your scripts grow, especially functions that are used over multiple scripts, using this strategy of globals is very dangerous. – Paul Hiemstra Oct 09 '12 at 15:35

4 Answers4

5
poco <- function() {

func <- function(x) {
    print(loco)
    loco <<- loco+x
}

loco <- 123
func(1)
func(2)
}

This <<- operator assigns to the outer scope. (like assign(..., env=...)). However, as mentioned in the comments, this is usually a bad idea. If you'd like to ask a second question expanding on this where you outline your entire problem, I bet there are other, better choices.

The <<- can bit you in the butt if you're not careful. See this wiki article

What was happening in your first function where you loco <- loco + x is that the function looks outside of the scope of func for loco when it finds it it brings in into the local scope of func and assigns to loco in the local scope rather than the poco scope.

Hope that helps!

Justin
  • 42,475
  • 9
  • 93
  • 111
  • Thanks all, answers and comments are appreciated, i will mark this as correct as it explains what i was doing wrong, but will also keep in mind the advice for avoiding this approach. – FUD Oct 09 '12 at 15:40
5

R has a stack of environments. So while you are changing a variable within a function with simple <- or = commands, its value will not change in the outer environment.

To do so, you have several options, as illustrated below:

1st Option:

func <- function(x) {
    print(loco)
    # To modify value of "loco" just in the parent environment, but not globally
    loco <<- loco+x
}

2nd (better) Option:

func <- function(x) {
    print(loco)
    # Again modifies the varaible just in the parent environment, not globally
    assign("loco", loco + x, envir = sys.frame(-1))
}

And the 3rd Option:

func <- function(x) {
    print(loco)
    # To modify the value of a global variable "loco"
    assign("loco", loco + x, envir = .GlobalEnv) 
}

then you will have:

loco <- 123
func(1) # 123
func(2) # 124
loco    # 126

Note that by using options 1 and 2, if you have several nested function definitions, you are modifying the value just in the parent function but not globally.

Ali
  • 9,440
  • 12
  • 62
  • 92
  • This answers the question, but might not be a good strategy in the long run. – Paul Hiemstra Oct 09 '12 at 15:34
  • excellent answer, i think the third option will be just awesome. Also does <<- translates to 2nd or 3rd option? – FUD Oct 09 '12 at 15:51
  • @FUD Thanks. I modified the answer, so it contains your answer now! – Ali Oct 09 '12 at 15:55
  • 1
    wish i could upvote twice ,thanks for taking the time to explain. – FUD Oct 09 '12 at 15:57
  • @FUD You are welcome. Maybe you can set the accepted answer, although Justin's answer is also great :) – Ali Oct 09 '12 at 15:58
  • @PaulHiemstra According to the question title, the function scope was needed to be illustrated, not just an assignment command – Ali Oct 09 '12 at 16:01
3
poco <- function() {

  func <- function(loco,x) {
    print(loco)
    loco <- loco+x
    loco
  }

  loco <- 123
  loco <- func(loco,1)
  loco <- func(loco,2)
  loco
}
loco_final <- poco()
#[1] 123
#[1] 124
loco_final
#[1] 126
Roland
  • 127,288
  • 10
  • 191
  • 288
  • I wanted to avoid just that because IF the value passed is large it could be a problem ( as value pass doesnt happen by reference in R ) – FUD Oct 09 '12 at 15:27
  • I don't think using a global variable would avoid that problem. But you are welcome to show us the problem. – Roland Oct 09 '12 at 15:30
  • @FUD This is the R way to do it though – Dason Oct 09 '12 at 15:31
  • Often you want to reduce a very big object, e.g. calculating a mean over some dimension. When this is not possible, you have to process in chunks, or ensure you roughly have 4-5 times the object size in RAM. For some more info see http://stackoverflow.com/questions/12767432/how-can-i-tell-when-my-dataset-in-r-is-going-to-be-too-large. – Paul Hiemstra Oct 09 '12 at 15:32
3

In general it is a good thing that loco is not changed in the function. Not using these kind of global variables ensures that variables do not interfere which each in larger scripts.

Let's say that you use a variable bla in function_a and function_b. Predicting the result of a function call is hard as it depends on the history of bla. In jargon this is called that the functions have side effects. Not using these makes the functions more predictable, and easier to debug. In addition, when your script grows, you prevent any problems with new functions or code snippets changing bla and thus changing what happens in the functions.

In general, if you need a variable in a function, pass it as a variable. However, R does allow scoping from inside the function to outside the function, but not vice-versa. See also this recent question for more information.

Community
  • 1
  • 1
Paul Hiemstra
  • 59,984
  • 12
  • 142
  • 149