forked from hadley/adv-r
-
Notifications
You must be signed in to change notification settings - Fork 0
/
Namespaces.rmd
116 lines (70 loc) · 7.3 KB
/
Namespaces.rmd
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
---
title: Namespaces
layout: default
---
# 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 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](Documenting-packages.html):
#' @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][S4] 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.
[S4]: http://cran.r-project.org/doc/manuals/R-exts.html#Name-spaces-with-S4-classes-and-methods