0

I have function like this:

myfun <- function ()
{
    df <<- data.frame(a = 1)
}
myfun()

but it reports an error "Error in myfun() : cannot change value of locked binding for 'df'". I really need to modify the global variable df and I don't care if I mask existing function. How can I do this?

I discovered this solution. It works, but is there something less complicated?

myfun <- function ()
{
    df <- data.frame(a = 1)
    assign("df", df, envir = .GlobalEnv)
}
myfun()
Tomas
  • 57,621
  • 49
  • 238
  • 373

2 Answers2

5

The best solution here would be to avoid handling the scope of the variables inside the function entirely. If you want to create a function which can be used to assign a data frame variable, then just have that function return the data frame:

myfun <- function() {
    df <- data.frame(a = 1)
    return(df)
}

# from some calling scope
mydf <- myfun()

If you want a data frame to be assigned inside a certain scope, then let that scope make the assignment, rather than having the function do this.

Tim Biegeleisen
  • 502,043
  • 27
  • 286
  • 360
  • I know this is possible, I am not a beginner ;-) If that was a solution for me I wouldn't be asking :-) My function returns lots of other variables as well. Solution with `attach(myfun())` is unnaceptable, since it is in a for loop. – Tomas Nov 05 '19 at 01:22
  • 1
    In general, if you need an R function to reach out and make assignments in some other scope, it can indicate a design smell. You likely shouldn't have the need to do this. – Tim Biegeleisen Nov 05 '19 at 01:26
  • That's idealistic thinking. Following it means long ugly code instead of simple elegant code... So this is a reason I am specifically asking about assigning to a global variable, this is not a solution. – Tomas Nov 05 '19 at 01:30
  • 2
    @TMS No, that's *functional* thinking. How is the example given by Tim "ugly code"? I would argue it's syntactically cleaner. The bottom line is you should not assign to a variable in the global environment using `<<-` or `assign`. There are quite a few posts here on SO that explain *why* this is a bad idea. If you want to avoid copying data, perhaps an option is to use a (pseudo-) OOP system like `R6` or reference classes. – Maurits Evers Nov 05 '19 at 01:49
3

There's not much to add to @TimBiegeleisen's answer; however, in response to your post and the error you see, you'd need to declare df outside of the function scope.

The following works

df <- data.frame()
myfun <- function () df <<- data.frame(a = 1)
myfun()
df
#  a
#1 1

Note however that this is not how <<- is supposed to be used, see Dirk Eddelbuettel's answer to "What is the difference between assign and <<- in R". To summarise:

  • you may use <<- to update an object in a parent (but not global) environment ("super-assignment" with lexical scope), and conversely
  • don't use <<- to update an object in the global environment.
Maurits Evers
  • 49,617
  • 4
  • 47
  • 68
  • if a `df` object is found on the way up before the intended `df` object it will be updated silently and debugging might be painful – moodymudskipper Feb 26 '20 at 10:51