2

Recently I have been working with a set of R scripts that I inherited from a colleague. It is for me a trusted source but more than once I found in his code auto-assignments like

x <<- x

Is there any scope where such an operation could make sense?

Ben Bolker
  • 211,554
  • 25
  • 370
  • 453
Manfredo
  • 1,760
  • 4
  • 25
  • 53

4 Answers4

4

This is a mechanism for copying a value defined within a function into the global environment (or at least, somewhere within the stack of parent of environments): from ?"<<-"

The operators ‘<<-’ and ‘->>’ are normally only used in functions, and cause a search to be made through parent environments for an existing definition of the variable being assigned. If such a variable is found (and its binding is not locked) then its value is redefined, otherwise assignment takes place in the global environment.

I don't think it's particularly good practice (R is a mostly-functional language, and it's generally better to avoid function side effects), but it does do something. (@Roland points out in comments and @BrianO'Donnell in his answer [quoting Thomas Lumley] that using <<- is good practice if you're using it to modify a function closure, as in demo(scoping). In my experience it is more often misused to construct global variables than to work cleanly with function closures.)

Consider this example, starting in an empty/clean environment:

f <- function() {
     x <- 1     ## assignment
     x <<- x    ## global assignment
}

Before we call f():

x
## Error: object 'x' not found

Now call f() and try again:

f()
x
## [1] 1
Ben Bolker
  • 211,554
  • 25
  • 370
  • 453
  • 1
    It's good practice if you make use of closures and don't use it to write into the global environment. See `demo(scoping)`. – Roland Sep 06 '16 at 15:54
1
<<- 

is a global assignment operator and I would imagine there should hardly ever be a reason to use it because it effectively causes side effects.
The scope to use it would be in any case when one wants to define a global variable or a variable one level up from current environment.

USER_1
  • 2,409
  • 1
  • 28
  • 28
  • 1
    ... technically, could assign multiple levels up from the current environment if it finds the symbol there ... – Ben Bolker Sep 06 '16 at 15:12
1

For example:

x <- NA

test <- function(x) {
 x <<- x
}

> test(5)
> x
#[1] 5

That's a simple use here, <<- will do a parent environment search (case of nested functions declarations) and if not found assign in the global environment.

Usually this is a really bad ideaTM as you have no real control on where the variable will be assigned and you have chances it will overwrite a variable used for another purpose somewhere.

Tensibai
  • 15,557
  • 1
  • 37
  • 57
  • technically, `<<-` goes up the stack of *parent frames* rather than up the *calling stack* - so nested functions aren't really relevant here, unless the functions are each defined within the functions they're called from (so that the call stack and the stack of enclosing environments are the same ...) – Ben Bolker Sep 06 '16 at 15:47
  • I'm unsure to get your comment, I've the feeling we're on the same line with different words. I was thinking about anonymous function within a sapply call in a function (to assign to a variable in the parent function scope and not within sapply scope). Or with function defining inner function depending on parameters. Maybe I'm not that clear here :/ – Tensibai Sep 06 '16 at 15:51
  • That said main point is that if the var doesn't exist in the parent scope it will end up in the global environment, which is dangerous. but you explained this better than me. – Tensibai Sep 06 '16 at 15:52
  • 1
    It's just that you say "case of nested functions". If I define `f()`, `g()`, `h()` in the global environment, call `f(g(h()))`, and do `x <<- x` within `h()`, it will do the assignment in the global environment (the parent frame of `h`), not in the environment of `g` or `f` (the environments farther up the calling stack) – Ben Bolker Sep 06 '16 at 15:53
  • Aww, yes, I was thinking about nested definitions, not nested calls. – Tensibai Sep 06 '16 at 15:54
1

Alan gives a good answer: Use the superassignment operator <<- to write upstairs.

Hadley also gives a good answer: How do you use "<<-" (scoping assignment) in R?.

For details on the 'superassignment' operator see Scope.

Here is some critical information on the operator from the section on Assignment Operators in the R manual:

"The operators <<- and ->> are normally only used in functions, and cause a search to be made through parent environments for an existing definition of the variable being assigned. If such a variable is found (and its binding is not locked) then its value is redefined, otherwise assignment takes place in the global environment."

Thomas Lumley sums it up nicely: "The good use of superassignment is in conjuction with lexical scope, where an environment stores state for a function or set of functions that modify the state by using superassignment."

Community
  • 1
  • 1
Brian O'Donnell
  • 1,836
  • 19
  • 29