3

I have a script of R which takes other scripts of R and manipulates them in such a way, and also executes their code. My script uses some variables (obviously), and when the other scripts use a common variable name, I get in a mess. I wish I could execute the other script like in a capsule, such that the coinciding variables do not affect each other.

I have been reading about environments, and have made a lot of trials, but I don't catch their real meaning.

Example:

script1.txt
___________
i=sample(10:20,1)

script2.txt
___________
i=sample(10:20,1) 

myscript.txt
___________
other.script = c("script1.txt", "script2.txt")
for( i in 1:2 ) {
    source(other.script[i])
}
i==2

I wish each variable "i" does its duty without affecting the other ones (specially the one in myscript, I don't care much about the other ones).

RichardTheKiwi
  • 105,798
  • 26
  • 196
  • 262
PabloGregori
  • 147
  • 1
  • 11
  • Could you just use another variable like j? It may be more helpful if you describe your setup and what you're attempting to do? – Tyler Rinker Oct 05 '12 at 17:23
  • 2
    @TylerRinker relying on names of variables being different can be tricky to get right if your script becomes too big. Abstraction into functions ensures variables are local to the functions, preventing any unwanted interactions. – Paul Hiemstra Oct 05 '12 at 18:00

2 Answers2

6

You are looking for sys.source. You were on the right track, you need to create an environment and then run the script inside that environment.

other.script = c("script1.txt", "script2.txt")
for( i in 1:2 ) {
  env<-new.env(parent = baseenv())
  sys.source(other.script[i],env)
  print(get('i',env)) # prints the value of i
}
i==2 # TRUE
nograpes
  • 18,623
  • 1
  • 44
  • 67
  • 1
    +1, although having a script being executed in its own environment and retrieving the result for later use in the script sounds awfully close to the concept of a function. – Paul Hiemstra Oct 05 '12 at 17:59
  • Yes, I agree. However, I can think of a few cases where this would be useful. Imagine you assigned some homework to a class, and you told them to store their answer in some final variable. You would collect all the submissions as files, and then try to run each one successively. Contrived, I know, but not an entirely impossible use-case. – nograpes Oct 05 '12 at 18:36
  • 1
    I totally agree there might be use cases for it, but I would generally try to avoid it. – Paul Hiemstra Oct 05 '12 at 18:43
6

The best way to deal with this is to create a set of functions which cut up the functionality captured by your scripts. Each function is executed in its own environment, preventing variables getting in each others way. Ideally, functions shouldn't be too long, say 10-20 lines or code. A larger script than calls these functions to get stuff done. If you do this correctly, your scripts can be short and to the point. I usually store these functions in one or more script files, ready to be sourceed by scripts needing them. You could even wrap them in a package.

The way you want to order your script, all variables are global, i.e. accessible throughout the whole program. In general, global variables should be avoided like the plague. This is precisely because of what your question focuses on: how do I keep variables from interfering with each other. Like I said, abstraction into functions or objects is the way to keep this from happening. More information on global variables and such can be found there:

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