diff --git a/_pkgdown.yml b/_pkgdown.yml index 725495af..c5f08c2b 100644 --- a/_pkgdown.yml +++ b/_pkgdown.yml @@ -44,6 +44,7 @@ articles: - generics-methods - classes-objects - compatibility + - packages - motivation - performance diff --git a/vignettes/compatibility.Rmd b/vignettes/compatibility.Rmd index d7255af4..bb8693e6 100644 --- a/vignettes/compatibility.Rmd +++ b/vignettes/compatibility.Rmd @@ -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 @name in package code - #' @rawNamespace if (getRversion() < "4.3.0") importFrom("S7", "@") - NULL - - # enable usage of @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) - } - ``` +## diff --git a/vignettes/packages.Rmd b/vignettes/packages.Rmd new file mode 100644 index 00000000..06265a01 --- /dev/null +++ b/vignettes/packages.Rmd @@ -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 . + +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 . + +## 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 @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.