Advanced R by Hadley Wickham


Namespaces

As the name suggest, namespaces provide “spaces” for “names”, providing a context for evaluating which object is found when you look for it. When developing code, they allow you to specify which package to look for a function when there are multiple packages it could come from, and when developing packages they ensure that your functions always call functions in the same place.

Namespaces make it possible for packages to refer to specific functions in other packages, not the functions that you have defined in the global workspace.

For example, take the simple nrow function:

nrow
# function (x) 
# dim(x)[1L]

What happens if we create our own dim method? Does nrow break?

dim <- function(x) c(1, 1)
dim(mtcars)
nrow(mtcars)

Suprisingly, it does not! That’s because when nrow looks for an object called dim, it finds the function in the base package, not our function.

Namespaces also provide an extension to the standard way of looking up the value of an object: instead of just typing objectname, you type package::objectname.

Namespaces also control the functions and methods that your package makes available for use by others. Namespaces make it easier to come up with your own function names without worrying about what names other packages have used. A namespace means you can use any name you like for internal functions, and when there is a conflict with an exported function, there is a standard disambiguation procedure.

The easiest way to use namespaces is with roxygen2, because it keeps the namespace definitions next to the function that it concerns. The translation between roxygen2 tags and NAMESPACE directives is usually straightforward: the tag becomes a function name and its space-separated arguments become comma separated arguments to the function. For example @import plyr becomes import(plyr) and @importFrom plyr ddply becomes importFrom(plyr, ddply). The chief exception is @export which will automatically figure out the function name to export.

How do namespaces work

Exporting

For every function in your package, you need to decide whether it is external and available to all users of the package, or internal and only available to other functions within the package. It’s not always easy to tell whether or not a function is internal or external. A few rules of thumb:

  • Is the purpose of the function the same as the purpose of the package? If not, make it internal. (A package should provide a set of closely related functions for a well-defined problem domain - someone should be able to look at all the functions in your package and say this is a package about X - if not, you should consider splitting it up into two packages)

  • Does the function have a clear purpose and can you easily explain it? Every external function needs to be documented, and there’s an implicit contract that that function will continue to exist in the future. If that’s not the case, don’t export it.

If a function isn’t exported, you don’t need to document it. This doesn’t mean you shouldn’t document it, but you only need to if it’s complicated enough that you think you won’t remember what it does. Generally, you want to export as few functions as possible: this makes it easier to change the package in the future.

As described below, the @export tag is all that you need. There are only a few exceptions:

  • Functions: use the @export tag.

  • S3 methods: There are two ways to export a method for an S3 method depending on whether it’s documented or not:

    • If it’s documented, you’ll already be using the @method tag to state that it’s an S3 method and you only need the @export to generate the correct export flag in the NAMESPACE

    • If it’s not documented, use the S3method tag: @S3method function class

  • S4 classes: Use @export

  • S4 methods: If the methods are for classes that you have defined and exported, you don’t need to do anything. If they are for classes defined in other packages, you need to use @export.

  • Other objects: For any other types of object that you want to make available to the user, use @export.

You may also want to make the distinction between functions for users and functions for other developers. Functions that might be useful for developers or power users should be exported, but tagged with @keywords internal so they don’t show up in routine lists of function documentation.

Importing

In your package DESCRIPTION there are two ways to indicate that your package requires another package to work: by listing it in either Depends or Imports. Depends works just like using library to load a package, but Imports is a little more subtle: the dependency doesn’t get loaded in a way the user can see. This is good practice because it reduces the chances of conflict, and it makes the code clearer by requiring that every package used be explicitly loaded. Since R 2.14 there is no reason to use Depends because all packages have a namespace.

There are two places you need to record your package’s dependency:

  • In the Imports field in the DESCRIPTION file, used by install.packages to download package dependencies automatically.

  • In the NAMESPACE file, to make all the functions in the dependency available to your code. The easiest way to do this is to add @import package-name to your package documentation:

    #' @docType package
    #' ...
    #' @import stringr MASS

and have roxygen2 generate the NAMESPACE file from that.

There are two alternatives to using @import:

  • Use @importFrom package fun1 fun2 ... to only import selected functions from another package. This is important if you are importing two packages share functions with the same name. You can also use it to produce a very specific NAMESPACE, but at the cost of having to use @importFrom for every function that uses a function from another package.

  • :: refers to a function within a package directly. I don’t recommend this method because it doesn’t work well during package development – it will use the installed version of the package, rather than the development version.

  • S4 methods: See the R extensions manual

You should very very very rarely use :::. This is a sign that you’re using an internal function from someone else - and there is no guarantee that that function won’t change from version to version. It would be better to encourage the author to make it an external, exported function, or ask if you could include a copy of it in your package.

Compiled code

If you have C or Fortran code in your package, you’ll need to add @useDynLib mypackage to your package documentation to ensure your functions can access it. This means you don’t need to specify PACKAGE in .Call.

How do they work

New set of rules on top of ordinary [[scoping]] rules, which deal with lists of environments - each environment belongs to a package. Search path. Variable look up differs depending on whether you’re inside or outside a package. If a package has a namespace, then R looks first inside the package namespace, then the imports, then the base namespace and then the normal search path.