Skip to content

Commit

Permalink
Start on packages vignette (#312)
Browse files Browse the repository at this point in the history
Fixes #306. Fixes #302.
  • Loading branch information
hadley authored Jul 18, 2023
1 parent 5ec5a64 commit 2b5f301
Show file tree
Hide file tree
Showing 3 changed files with 77 additions and 27 deletions.
1 change: 1 addition & 0 deletions _pkgdown.yml
Original file line number Diff line number Diff line change
Expand Up @@ -44,6 +44,7 @@ articles:
- generics-methods
- classes-objects
- compatibility
- packages
- motivation
- performance

Expand Down
28 changes: 1 addition & 27 deletions vignettes/compatibility.Rmd
Original file line number Diff line number Diff line change
Expand Up @@ -154,30 +154,4 @@ foo

S7 unions allow you to restrict the type of a property in the same way that S4 unions allow you to restrict the type of a slot.

## Using S7 in a package

If you are using S7 in a package *and* you want your package to maintain compatibility with R versions prior to 4.3.0, there are a few things to be aware of.

#### `@`

`` base::`@` `` in R versions prior to R 4.3.0 does not resolve R7 properties.

Workarounds:

- Use `S7::prop()` instead of `@`.

- Alternatively, make an S7-aware `@` available to your package with a custom `NAMESPACE` directive and `.onAttach()` like this:

``` r
# enable usage of <S7_object>@name in package code
#' @rawNamespace if (getRversion() < "4.3.0") importFrom("S7", "@")
NULL

# enable usage of <S7_object>@name in user code
# e.g. if you also want users to be able to access properties
# of objects your package
.onAttach <- function(libname, pkgname) {
if (getRversion() < "4.3.0")
require(S7)
}
```
##
75 changes: 75 additions & 0 deletions vignettes/packages.Rmd
Original file line number Diff line number Diff line change
@@ -0,0 +1,75 @@
---
title: "Using S7 in a package"
output: rmarkdown::html_vignette
vignette: >
%\VignetteIndexEntry{packages}
%\VignetteEngine{knitr::rmarkdown}
%\VignetteEncoding{UTF-8}
---

```{r, include = FALSE}
knitr::opts_chunk$set(
collapse = TRUE,
comment = "#>"
)
```

This vignette outlines the most important things you need to know about using S7 in a package.
S7 is new, so few people have used it in a package yet; this means that this vignette is likely incomplete, and we'd love your help to make it better.
Please [let us know](https://github.com/RConsortium/OOP-WG/issues/new) if you have questions that this vignette doesn't answer.

```{r setup}
library(S7)
```

## Method registration

You should alwys call `methods_register()` in your `.onLoad()`:

```{r}
.onLoad <- function(...) {
S7::methods_register()
}
```

This is S7's way of registering methods, rather than using export directives in your `NAMESPACE` like S3 and S4 do.
This is only strictly necessary if registering methods for generics in other packages, but there's no harm in adding it and it ensures that you won't forget later.
(And if you're not importing S7 into your namespace it will quiet an `R CMD check` `NOTE`.`)`

## Documentation and exports

If you want users to create instances of your class, you will need to export the class constructor.
That means you will also need to document it, and since the constructor is a function, that means you have to document the arguments which will be the properties of the class (unless you have customised the constructor).

You should document generics like regular functions (since they are!).
If you expect others to create their own methods for your generic, you may want to include an section describing the the properties that you expect all methods to have.
We plan to provide a an easy way to all methods for a generic, but have not yet implemented it.
You can track progress at <https://github.com/RConsortium/OOP-WG/issues/167>.

We don't currently have any recommendations on documenting methods.
There's no need to document them in order to pass `R CMD check`, but obviously there are cases where it's nice to provide additional details for a method, particularly if it takes extra arguments compared to the generic.
We're tracking that issue at <https://github.com/RConsortium/OOP-WG/issues/315>.

## Backward compatibility

If you are using S7 in a package *and* you want your package to work in versions of R before 4.3.0, you need to know that in these versions of R `@` only works with S4 objects.
There are two workarounds.
The easiest and least convenient workaround is to just `prop()` instead of `@`.
Otherwise, you can conditionally make an S7-aware `@` available to your package with this custom `NAMESPACE` directive:

``` r
# enable usage of <S7_object>@name in package code
#' @rawNamespace if (getRversion() < "4.3.0") importFrom("S7", "@")
NULL
```

You can additionally make `@` work for users of your package by attaching the S7 package when your package is attached with this `.onAttach()` code:

```{r}
.onAttach <- function(libname, pkgname) {
if (getRversion() < "4.3.0")
require(S7)
}
```

Use this technique with care as it will attach S7 to the user search path, possibly causing conflicts with other packages/functions.

0 comments on commit 2b5f301

Please sign in to comment.