hotpatchR-intro.RmdThis vignette explains the hotpatchR design and why
runtime namespace patching is the right tool for legacy hotfix
workflows.
A loaded R package lives in a locked namespace. That means internal functions are resolved from inside the package bubble. When one internal function calls another, R does not look in the global environment.
So if you fix a_freq_j() in the global environment,
tt_to_tlgrtf() inside the package still calls the original
broken version.
This is the namespace trap that makes legacy hotfixing so difficult.
The usual workaround is:
This is painful because a bug in one internal function can require copying many internal callers, even when only one implementation actually needs to change.
Instead of pulling functions out into the global environment,
hotpatchR performs surgical edits inside the package
namespace. That means:
# Simulate a locked package environment.
pkg_env <- new.env()
pkg_env$broken_child <- function() "I am broken"
pkg_env$parent_caller <- function() pkg_env$broken_child()
lockEnvironment(pkg_env)
lockBinding("broken_child", pkg_env)
lockBinding("parent_caller", pkg_env)
# Apply the patch.
fixed_child <- function() "I am FIXED"
inject_patch(pkg_env, list(broken_child = fixed_child))
pkg_env$parent_caller()
#> [1] "I am FIXED"If pkg_env were a real package namespace, the same
internal caller would now use the patched
broken_child().
Because the replacement function’s parent environment is set to the target namespace, it can still call other internal objects from the same package.
If you need to restore the original binding,
undo_patch() reverses the previous change.
undo_patch(pkg_env, "broken_child")
pkg_env$parent_caller()
#> [1] "I am broken"apply_hotfix_file() is a convenience wrapper for
scripting hotfix application. A compatible hotfix script should
define:
pkg (optional, if not passed explicitly)patch_list, a named list of replacement functionsExample hotfix file:
pkg <- "junco"
patch_list <- list(
a_freq_j = function(...) {
# fixed implementation
}
)Then apply it with:
apply_hotfix_file("dev/junco_hotfix_v0-1-1.R")