The problem here is related to scope.
In R, every variable is stored in an environment.
- There is a global environment which stores "top-level" variables. This is sometimes called the workspace or workspace environment.
- There are package environments (actually two per package: one public and one private).
- You can create custom environments with
new.env()
.
- You can copy data.frames, lists, and existing
save()
files to new environments with attach()
, but this is discouraged.
- There are a few fairly obscure and usually unimportant environments, such as the empty environment and the Autoload environment.
- Finally, a new environment is created for each evaluation of a function, which is referred to as the evaluation environment for that particular evaluation of that particular function.
The documentation on assign()
is a bit scattered when it comes to communicating exactly which environment receives the variable-to-be-assigned, but I'll try to quote all the relevant passages:
pos where to do the assignment. By default, assigns into the current environment. See ‘Details’ for other possibilities.
envir the environment to use. See ‘Details’.
The pos argument can specify the environment in which to assign the object in any of several ways: as -1 (the default), as a positive integer (the position in the search list); as the character string name of an element in the search list; or as an environment (including using sys.frame to access the currently active function calls). The envir argument is an alternative way to specify an environment, but is primarily for back compatibility.
Note that assignment to an attached list or data frame changes the attached copy and not the original object: see attach and with.
If no envir is specified, then the assignment takes place in the currently active environment.
If inherits is TRUE, enclosing environments of the supplied environment are searched until the variable x is encountered. The value is then assigned in the environment in which the variable is encountered (provided that the binding is not locked: see lockBinding: if it is, an error is signaled). If the symbol is not encountered then assignment takes place in the user's workspace (the global environment).
If inherits is FALSE, assignment takes place in the initial frame of envir, unless an existing binding is locked or there is no existing binding and the environment is locked (when an error is signaled).
Because you have not specified any of the pos
, envir
, or inherits
arguments in your assign()
call, the variable ends up being assigned into the "current" aka "active" environment. Because the assign()
call takes place inside of a call to your multi.csv()
function, the "current" aka "active" environment is the evaluation environment of that particular evaluation of your multi.csv()
function. When the evaluation of multi.csv()
completes, the environment is destroyed, and the variable is destroyed with it (note: closuring an evaluation environment prevents it from being destroyed, but your code is not doing any closuring, so that doesn't apply here).
This also helps to explain why your top-level call to assign()
works: because the "current" aka "active" environment in that case is the global environment, so the variable lands right where you expect it: in your workspace environment.
You can solve the problem by passing pos=1L
or envir=globalenv()
in your assign()
call.
(You could also solve the problem by passing inherits=T
, which is akin to using the superassignment operator <<-
, but this is discouraged.)
See here for more information.