Tim
Tim

Reputation: 325

R: Scoping error when calling function from script

I am building a large codebase in R that uses vectorization through many nested user-defined functions. These auxiliary functions are, by in large, written in their own R script for debugging and maintenance purposes. I would like to source some of these scripts within a specific environment, without the functions being called into the Global Environment.

I am trying to make the main.R file as clean and understandable as possible, so that there are scripts that do the dirty work behind the scenes.

In the example below, the global environment becomes populated with f_foobar (which is correct), but also f_foo and f_bar once I call the function f_foobar.

Is there an elegant way to house these auxiliary functions (eg f_foo and f_bar) in a temporary environment?

For example, in file_foo.R:

f_foo <- function() {
  return('a')
}

In file_bar.R:

f_bar <- function() {
  return('b')
}

In file_foobar.R:

f_foobar <- function() {
  source('file_foo.R')
  source('file_bar.R')
  
  value_foo <- f_foo()
  value_bar <- f_bar()
  
  c(value_foo, value_bar) %>% return
}

In main.R:

source('file_foobar.R')

main_result <-f_foobar()

Upvotes: 0

Views: 53

Answers (1)

r2evans
r2evans

Reputation: 160407

Bottom line: use source(..., local=TRUE). From ?source:

   local: 'TRUE', 'FALSE' or an environment, determining where the
          parsed expressions are evaluated.  'FALSE' (the default)
          corresponds to the user's workspace (the global environment)
          and 'TRUE' to the environment from which 'source' is called.

Before

ls()
# character(0)
source('file_foobar.R')
main_result <- f_foobar()
main_result
# [1] "a" "b"
ls()
# [1] "f_bar"       "f_foo"       "f_foobar"    "main_result"

After

ls()
# character(0)
source('file_foobar.R')
main_result <- f_foobar()
main_result
# [1] "a" "b"
ls()
# [1] "f_foobar"    "main_result"

(But really, when you talk about "within a specific environment", that really does speak to using an R package. There are many benefits to doing so, even if you never have the intention of pushing to CRAN. I have about two dozen packages I maintain at work, not CRAN, and while I might be able to scope them individually without being a package, the moment you even consider using one project from another, it becomes unnecessarily complex. Packages almost always solve that.)

Upvotes: 1

Related Questions