R Name Resolution
R has a peculiar way of resolving names within packages. This confused me when I first started developing R packages, because similar code would behave differently in packages and in scripts.
The R search path within a package can be divided into two halves: The package-specfic part and the global part. The package-specific part consists of symbols that are only available within the package. The global part refers to symbols that are available outside the package (within the lexical scope of some particular call to a package function).
The Package-Specific Part
When you use a name inside of a package in R, the first place that R will look for it is within the package itself. It will check, in this order:
- The Package Namespace: within the package proper (i.e., the source code that you wrote)
- The Imports Environment: within one of the packages included in the
Imports:
orDepends:
sections of theDESCRIPTION
- The Base Namespace: This is a special environment which is basically just a copy of the base environment. It’s included here to allow you to use base functions without qualifying them with
base::
.
The Global Part
Now, if the name isn’t found in any of these places we will search the environment where the package was called. This means searching:
- The Global Environment
- The Package Environments of attached packages: meaning symbols that other packages export, not their internal search paths
- The Base Package Environment: This will never be used from within a package, because you will get a hit in the Base Namespace first, but it’s included because it’s part of the global search path.
You can see how this would work from within the stats
package below. This example is slightly confusing because stats
shows up 3 times. The first (namespace:stats
) is because we are within the stats
package and we check there first. The second (imports:stats
) doesn’t actually include symbols exported by stats
, but rather symbols exported by the packages that stats
imports via its NAMESPACE
file (generated by the Imports:
field of its DESCRIPTION
). The third (package:stats
) is there by virtue of stats
having been attached with a call to library(stats)
before being used.
To quote from the R Internals manual:
Namespaces are environments associated with packages (and once again the base package is special and will be considered separately). A package
pkg
defines two environmentsnamespace:pkg
andpackage:pkg
: it ispackage:pkg
that can be attached and form part of the search path.The objects defined by the R code in the package are symbols with bindings in the
namespace:pkg
environment. Thepackage:pkg
environment is populated by selected symbols from thenamespace:pkg
environment (the exports). The enclosure of this environment is an environment populated with the explicit imports from other namespaces, and the enclosure of that environment is the base namespace. (So the illusion of the imports being in the namespace environment is created via the environment tree.) The enclosure of the base namespace is the global environment, so the search from a package namespace goes via the (explicit and implicit) imports to the standard ‘search path’.The base namespace environment
R_BaseNamespace
is anotherENVSXP
that is special-cased. It is effectively the same thing as the base environmentR_BaseEnv
except that its enclosure is the global environment rather than the empty environment: the internal code diverts lookups in its frame to the global symbol table.