0

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()
2
  • 2
    "Is there an elegant way..." yes, create a package. Commented Mar 9, 2021 at 15:55
  • +1 for the package. But I suggest you read ?source, particularly: local: ... 'FALSE' (the default) corresponds to the user's workspace (the global environment) and 'TRUE' to the environment from which 'source' is called. Use source("file_foo.R", local=TRUE), and your scoping should be resolved. (But really ... a package.) Commented Mar 9, 2021 at 16:07

1 Answer 1

1

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.)

Sign up to request clarification or add additional context in comments.

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.