Code
sum = function (x) {
S = 0
for (i in x) {
S = S + i
}
S
}When working with modules during development, you’ll frequently modify the source code, and need those changes to reflect in your current R session, especially when debugging. Understanding how {box} handles module reloading to increase development workflow efficiency.
This section primarily applies to modules created from scripts and folders, not R packages loaded from CRAN or other repositories.
By default, {box} caches modules after the first import. This improves performance but means changes to your module files won’t automatically appear in your current session.
In this example, imagine you have ./utils/helpers:
box::use(./utils/helpers)
helpers$my_function() # Works as expectedThen eventually, you made some modification to helpers.r and run the import again in the same session:
box::use(./utils/helpers)
helpers$my_function() # Still uses old version!Here’s the problem: second import that uses box::use(), uses cached version, and the changes you made in ./utils/helpers will NOT be reflected.
There are some reasons why caching happens:
This behavior mirrors how R packages work. Once loaded with library(), they remain in memory until the session restarts.
After you load ./utils/helpers as a helpers module, reload helpers with box::reload().
To see changes made to a module without restarting R, see what I mean:
You already did an initial import of ./utils/helpers, saved as ./helpers module:
box::use(./utils/helpers)Make some changes in ./utils/helpers whatever you want
Reload ./helpers to modify the cached module
box::reload(helpers)The practical examples are provided below that you can replicate in your current sessions somewhere. First, create ./utils/ folder then create an R script named helpers.r. Once ./utils/helpers is loaded through box::use(./utils/helpers), helpers module is now loaded and cached into the current environment.
To be enlightened, here’s three (3) scenarios when you made some changes and then reload the helpers/ module:
Here’s what ./utils/helpers is made of:
sum = function (x) {
S = 0
for (i in x) {
S = S + i
}
S
}Then, in your R session:
box::use(./utils/helpers)
x = 1 : 10
helpers$sum(x) Then, suddenly you changed your mind because you figured out that it will not work once the vector x contains missing values NA. And so, you made another modification:
box::use(
stats[na.omit]
)
sum = function (x, na.rm = FALSE) {
if (na.rm) {
x = na.omit(x)
}
S = 0
for (i in x) {
S = S + i
}
S
}Instead of loading the module through box::use() again, reload helpers to utilize the changes made instead:
box::reload(helpers)
x = 1 : 10
x[4] = NA
helpers$sum(x)
#> 51Originally, ./utils/helpers contains only 1 function. How about we made changes in helpers module by adding new functions?
For example, you want a new function ./utils/helpers that calculates the mean:
box::use(
stats[na.omit]
)
sum = function (x, na.rm = FALSE) {
if (na.rm) {
x = na.omit(x)
}
S = 0
for (i in x) {
S = S + i
}
S
}
mean = function (x, na.rm = FALSE) {
if (na.rm) {
x = na.omit(x)
}
S = sum(x)
n = length(x)
out = S / n
out
}Since it caches the recent ./utils/helpers import, mean() from helpers won’t be available, thus a simple error.
x = 1 : 10
x[4] = NA
helpers$mean(x, na.rm = TRUE)
#> Error in helpers$mean : name 'mean' not found in 'helpers'Once again, reload helpers module:
box::reload(helpers)And helpers$mean() is now available:
x = 1 : 10
x[4] = NA
helpers$mean(x, na.rm = TRUE)
#> [1] 5.7What if we only export mean() from ./utils/helpers? By the way, box::export() is used to explicitly declare module exports, but fortunately, {box} borrows Roxygen2 API, and this includes #' @export.
box::use(
stats[na.omit]
)
sum = function (x, na.rm = FALSE) {
if (na.rm) {
x = na.omit(x)
}
S = 0
for (i in x) {
S = S + i
}
S
}
#' @export
mean = function (x, na.rm = FALSE) {
if (na.rm) {
x = na.omit(x)
}
S = sum(x)
n = length(x)
out = S / n
out
}Reload helpers with box::reload() and sum() is not one of the exports from helpers module now. To see what it means:
box::reload(helpers)
x = 1 : 10
x[4] = NA
helpers$mean(x, na.rm = TRUE)
#> [1] 5.7
helpers$sum(x, na.rm = TRUE)
#> Error in helpers$sum : name 'sum' not found in 'helpers'The function box::reload() ONLY reloads the module, not the functions or objects under the namespace of the module. Trying to reload function will throw an error saying Error in box::reload(custom_mean) : "reload” expects a module object, got “fun”, which is of type “function” instead
box::use(
./utils/helpers[custom_mean = mean]
)
box::reload(custom_mean)
#> Error in box::reload(custom_mean) :
#> “reload” expects a module object, got “custom_mean”, which is of type “function” insteadThe best solution is to restart the session, and the environment/s created by box::use() will absolve, and once again, the current environment is now cleansed.
To be frank, an R session is simply just a running instance of the R interpreter. The environment where R executes code, stores objects, and manages the workspace. When you start R (via terminal, RStudio, VS Code, or any other interface), you are launching a fresh R session.
The question is, when to use box::reload() versus restarting your R session?
Use box::reload() when:
Restart R session when:
box::use(), only accepting modules.box::use().In RStudio, restart R with Ctrl/Cmd + Shift + F10. This clears everything and gives you a fresh start without closing RStudio.