rr-packager-s4

Is there a way to use own package's data (internal or external) as a default S4 class slot?


Is there a way to use my own package's data (internal or external) as a default S4 class slot?

If I create some package data:

my_pkg_data <- sample(100)

usethis::use_data(my_pkg_data, internal=FALSE)

I can make functions taking the data as a default parameter:

#' Title
#'
#' @param x foo
#'
#' @return nout
#' @export
#'
foo <- function(x = test::my_pkg_data) {

  print(x)

}

#run
foo() 
   [1]  407  184   13  994  933  322  214  784  502  396  903 ....

However, if creating S4 classes I get an error running devtools::check():

#' Title
#'
#' @slot some_slot ...
#' @return a s4class object
#' @export
#'
s4class <- setClass(
  Class = "s4class",
  slots = list(
    some_slot = "ANY"
  ),
  prototype = list(
    some_slot = test::my_pkg_data
  )
)

devtools::check()

* installing *source* package ‘test’ ...
** using staged installation
** R
** data
*** moving datasets to lazyload DB
** byte-compile and prepare package for lazy loading
Error : 'my_pkg_data' is not an exported object from 'namespace:test'
Error: unable to load R code in package ‘test’
Execution halted
ERROR: lazy loading failed for package ‘test’
* removing ‘/private/var/folders/62/n2yrhw752hn73nlbzp0r0_rr0000gq/T/RtmpvHbEA2/file36f3594c2270/test.Rcheck/test’

1 error ✖ | 0 warnings ✔ | 0 notes ✔

DESCRIPTION:

Package: test
Title: What the Package Does (One Line, Title Case)
Version: 0.0.0.9000
Authors@R: 
    person("First", "Last", , "first.last@example.com", role = c("aut", "cre"),
           comment = c(ORCID = "YOUR-ORCID-ID"))
Description: What the package does (one paragraph).
License: MIT + file LICENSE
Encoding: UTF-8
Roxygen: list(markdown = TRUE)
RoxygenNote: 7.2.3
Depends: 
    R (>= 2.10)
LazyData: true

NAMESPACE:

# Generated by roxygen2: do not edit by hand

export(foo)
export(s4class)
exportClasses(s4class)

data.R file:

#' @title my data
#' @name my_pkg_data
"my_pkg_data"

Is this possible? Do I have to do this in an S4 initialise function instead? What's the reason behind this?

for example this works:

setMethod(
  f = "initialize",
  signature = "s4class",
  definition = function(.Object, some_slot=test::my_pkg_data) {
    .Object@some_slot <- some_slot
    validObject(.Object)
    return(.Object)
  }
)

Thanks,


Solution

  • setClass is called at install time and almost always evaluates its prototype argument, hence the error. You'd encounter a similar error at install time if under the definition of foo you tried to evaluate a call such as foo().

    In your situation, I would simply define a method for initialize:

    > tools::assertError(Matrix::USCounties) # an error, as not lazy-loaded
    > setClass("zzz", slots = c(x = "ANY"))
    > setMethod("initialize", "zzz",
    +           function(.Object, ...) {
    +               .Object <- callNextMethod(.Object, ...)
    +               if (all(...names() != "x")) {
    +                   data(USCounties, package = "Matrix", envir = environment())
    +                   .Object@x <- USCounties
    +               }
    +               .Object
    +           })
    > z1 <- new("zzz")
    > data(USCounties, package = "Matrix")
    > stopifnot(identical(z1, new("zzz", x = USCounties)))