This question is similar to the next post , because I am still not completely convinced that in terms of code reliability, it would be far better to do a typification of namespace::foo()
instead of just typing foo()
and praying to get the desired result ; -)
Actual question
I know this applies pretty much to the “standard R conventions,” but let me say that I'm curious ;-) Can I somehow attach a temporary namespace to the search path?
Motivation
At the moment when my mypkg
package is still in a "developmental stage" (i.e. not a real R package yet ):
- I would like to pass my functions to
mypkg
environment instead of .GlobalEnv
- then attach
mypkg
to the search path (as soon as possible to the true namespace) - to be able to call
mypkg::foo()
I understand perfectly well that the ::
call has its drawbacks (it takes more time than just entering the function name and let R handle the search implicitly) and / or may not be considered necessary because of the way a) R scans the search path and b) packets can import your dependencies (that is, use "Import" instead of "Depends", rather than export certain functions, etc.). But I saw how my code crashed at least twice due to the fact that certain (basic) functions were rewritten in some package, so I switched from "blind trust" to the mode "better to be safe than sorry ; -)
What i tried
AFAIU, namespaces are basically nothing more than some kind of special kind of environment
> search() [1] ".GlobalEnv" "package:stats" "package:graphics" [4] "package:grDevices" "package:utils" "package:datasets" [7] "package:methods" "Autoloads" "package:base" > asNamespace("base") <environment: namespace:base>
And there is an attach()
function that attaches objects to the search path. So here is what I thought:
temp.namespace <- new.env(parent=emptyenv()) attach(temp.namespace) > asNamespace("temp.namespace") Error in loadNamespace(name) : there is no package called 'temp.namespace'
I think I will have to work with attachNamepace()
and find out what this expects before it is called in library()
. Any ideas?
EDIT
Regarding Hadley's comment: I wouldn’t care if the nested environment is a full namespace or just an ordinary environment if I can extend ::
while maintaining the function of syntactic narrowing (i.e. the ability to call pkg::foo()
instead "::"(pkg="pkg", name="foo")()
).
Here's what the "::"
function looks like:
> get("::") function (pkg, name) { pkg <- as.character(substitute(pkg)) name <- as.character(substitute(name)) getExportedValue(pkg, name) }
This is what it should also do if R discovers that pkg
is actually not a namespace, but simply an environment tied to a search path:
"::*" <- function (pkg, name) { pkg <- as.character(substitute(pkg)) name <- as.character(substitute(name)) paths <- search() if (!pkg %in% paths) stop(paste("Invalid namespace environment:", pkg)) pos <- which(paths == pkg) if (length(pos) > 1) stop(paste("Multiple attached envirs:", pkg)) get(x=name, pos=pos) }
This works, but there is no syntactic sugar:
> "::*"(pkg="tempspace", name="foo") function(x, y) x + y > "::*"(pkg="tempspace", name="foo")(x=1, y=2) [1] 3
How can I call pkg::*foo(x=1, y=2)
(without considering the fact that ::*
is really a bad name for the function ;-))?