19

I have encountered a bit of a hiccup in something I'm working on. Suppose I have the following simple example. Let...

v <- c(606:608) ## Some vector of integers

I also, have a separate script written (let's just call it foo.R) which has something like (uses the RODBC package):

um <- sqlQuery(artemis,paste("select * from port.tdtf_VaR_Unmatched (",LatestModelRun,")",sep=""))

Now suppose I want to run the following loop function:

test <- function() {
 for (i in 1:length(v)) {
  LatestModelRun <- v[i]
  source("C:/R/foo.r")
  print(unmatched)} }

test() ## Run it

When I do this, I get the following error: Error in paste("\n\tselect * from port.tdtf_VaR_Unmatched (", LatestModelRun, : object 'LatestModelRun' not found

So, somehow it's not reading in the LatestModelRun variable defined within the test function.

Here's the traceback():

7: paste("\n\tselect * from port.tdtf_VaR_Unmatched (", LatestModelRun, 
   ")\n\twhere [PortfolioProduct] not in ('REC - Generic','REC - Green-e NY')\n\torder by [PortfolioProduct], [Year]", 
   sep = "")
6: odbcQuery(channel, query, rows_at_time)
5: sqlQuery(artemis, paste("\n\tselect * from port.tdtf_VaR_Unmatched (", 
   LatestModelRun, ")\n\twhere [PortfolioProduct] not in ('REC - Generic','REC - Green-e NY')\n\torder by [PortfolioProduct], [Year]", 
   sep = ""))
4: eval.with.vis(expr, envir, enclos)
3: eval.with.vis(ei, envir)
2: source("C:/R/foo.r")
1: test()

Anybody have an idea as to what I'm doing wrong??

Any help is much appreciated!! Thanks!!

Ray
  • 3,137
  • 8
  • 32
  • 59
  • I had this as an answer, but I decided I wasn't too sure about it, so I'll leave it as a comment instead. One simplistic solution would be to call the contents of `foo.r` as a function, rather than a script. – joran Jul 28 '11 at 18:52
  • Environment issue? In general I think @joran is right and you should call this as a function so you don't abuse globals. But if you're stuck with this approach, try explicit global assignment and evaluation. – Ari B. Friedman Jul 28 '11 at 18:55
  • 1
    By default the `source`'d code is evaluated in the global environment. Try setting `local=TRUE`, which will evaluate the code in the calling environment. – Joshua Ulrich Jul 28 '11 at 19:01
  • @gsk3 - Yeah, it appears `?source` defaults to evaluating in the global environment, but in the OP's traceback it appears the error may occur inside an altered environment (`eval.with.vis`). – joran Jul 28 '11 at 19:02

3 Answers3

39

As I said in my comment, the source'd code is evaluated in the global environment by default. Set local=TRUE to evaluate the code in the calling environment.

test <- function() {
  for (i in 1:length(v)) {
    LatestModelRun <- v[i]
    source("C:/R/foo.r", local=TRUE)
    print(unmatched)
  }
}
v <- c(606:608)
test()
# [1] "select * from port.tdtf_VaR_Unmatched (606)"
# [1] "select * from port.tdtf_VaR_Unmatched (607)"
# [1] "select * from port.tdtf_VaR_Unmatched (608)"

where foo.r contains:

unmatched <-
  paste("select * from port.tdtf_VaR_Unmatched (",LatestModelRun,")",sep="")
Joshua Ulrich
  • 173,410
  • 32
  • 338
  • 418
10

Joshua's answer is sweet & simple. I have a variant that allows you to be more explicit in how you pass parameters to the script:

test <- function() {
  for (i in 1:length(v)) {
    e <- new.env()
    e$LatestModelRun <- v[i]
    sys.source('c:/R/foo.R', e)
    print(e$unmatched)
  }
}

This uses the cousin to source; sys.source that allows you specify the environment. The environment can actually also be a list, so if you don't need any result variables from the script, you can simply passing in a list with the parameters you need:

sys.source('c:/R/bar.R', list(someparam=42, anotherparam=1:10))
Tommy
  • 39,997
  • 12
  • 90
  • 85
-1

Variables set in a function are not global, unless set by <<-, so wouldn't this work?

test <- function() {
 for (i in 1:length(v)) {
  LatestModelRun <<- v[i]
  source("C:/R/foo.r")
  print(unmatched)
 }
}
U. Windl
  • 3,480
  • 26
  • 54