From 89ff0c7b884d12afeb023d4c67b61e2358ee09e3 Mon Sep 17 00:00:00 2001 From: Tomasz Kalinowski Date: Mon, 4 Nov 2024 12:21:55 -0500 Subject: [PATCH] Use CamelCase for all class names in docs and vignettes. (#485) * Project-level canonical markdown `wrap: sentence` * update all `new_class()` usage in vignettes * update all `new_class()` usage in docs/examples * redocument * enable `workflow_dispatch` on R-CMD-check CI action * whitespace --- .github/workflows/R-CMD-check.yaml | 1 + R/S3.R | 2 +- R/S4.R | 8 +-- R/class.R | 20 +++--- R/convert.R | 28 ++++---- R/data.R | 4 +- R/external-generic.R | 4 +- R/inherits.R | 14 ++-- R/method-introspect.R | 10 +-- R/property.R | 26 ++++---- R/super.R | 44 ++++++------ S7.Rproj | 2 + man/S4_register.Rd | 8 +-- man/S7_class.Rd | 4 +- man/S7_data.Rd | 4 +- man/S7_inherits.Rd | 14 ++-- man/convert.Rd | 28 ++++---- man/method_explain.Rd | 10 +-- man/new_S3_class.Rd | 2 +- man/new_class.Rd | 16 ++--- man/new_external_generic.Rd | 4 +- man/new_property.Rd | 14 ++-- man/prop.Rd | 4 +- man/prop_names.Rd | 4 +- man/props.Rd | 4 +- man/super.Rd | 48 ++++++------- vignettes/S7.Rmd | 38 +++++------ vignettes/classes-objects.Rmd | 104 +++++++++++++++-------------- vignettes/compatibility.Rmd | 22 +++--- vignettes/generics-methods.Rmd | 26 ++++---- vignettes/performance.Rmd | 30 ++++----- 31 files changed, 275 insertions(+), 272 deletions(-) diff --git a/.github/workflows/R-CMD-check.yaml b/.github/workflows/R-CMD-check.yaml index e712a216..7f8062ef 100644 --- a/.github/workflows/R-CMD-check.yaml +++ b/.github/workflows/R-CMD-check.yaml @@ -5,6 +5,7 @@ # check-standard.yaml is likely a better choice. # usethis::use_github_action("check-standard") will install it. on: + workflow_dispatch: push: branches: [main, master] pull_request: diff --git a/R/S3.R b/R/S3.R index 89e7bdcf..5a801666 100644 --- a/R/S3.R +++ b/R/S3.R @@ -17,7 +17,7 @@ #' #' ```R #' method(my_generic, new_S3_class("factor")) <- function(x) "A factor" -#' new_class("my_class", properties = list(types = new_S3_class("factor"))) +#' new_class("MyClass", properties = list(types = new_S3_class("factor"))) #' new_union("character", new_S3_class("factor")) #' ``` #' diff --git a/R/S4.R b/R/S4.R index aa4c0375..6e7f05d6 100644 --- a/R/S4.R +++ b/R/S4.R @@ -12,11 +12,11 @@ #' standardGeneric("S4_generic") #' }) #' -#' foo <- new_class("foo") -#' S4_register(foo) -#' method(S4_generic, foo) <- function(x) "Hello" +#' Foo <- new_class("Foo") +#' S4_register(Foo) +#' method(S4_generic, Foo) <- function(x) "Hello" #' -#' S4_generic(foo()) +#' S4_generic(Foo()) S4_register <- function(class, env = parent.frame()) { if (!is_class(class)) { msg <- sprintf("`class` must be an S7 class, not a %s", obj_desc(class)) diff --git a/R/class.R b/R/class.R index f7d71135..29887e47 100644 --- a/R/class.R +++ b/R/class.R @@ -9,7 +9,7 @@ #' #' @param name The name of the class, as a string. The result of calling #' `new_class()` should always be assigned to a variable with this name, -#' i.e. `foo <- new_class("foo")`. +#' i.e. `Foo <- new_class("Foo")`. #' @param parent The parent class to inherit behavior from. #' There are three options: #' @@ -56,13 +56,13 @@ #' @export #' @examples #' # Create an class that represents a range using a numeric start and end -#' range <- new_class("range", +#' Range <- new_class("Range", #' properties = list( #' start = class_numeric, #' end = class_numeric #' ) #' ) -#' r <- range(start = 10, end = 20) +#' r <- Range(start = 10, end = 20) #' r #' # get and set properties with @ #' r@start @@ -70,11 +70,11 @@ #' r@end #' #' # S7 automatically ensures that properties are of the declared types: -#' try(range(start = "hello", end = 20)) +#' try(Range(start = "hello", end = 20)) #' #' # But we might also want to use a validator to ensure that start and end #' # are length 1, and that start is < end -#' range <- new_class("range", +#' Range <- new_class("Range", #' properties = list( #' start = class_numeric, #' end = class_numeric @@ -89,10 +89,10 @@ #' } #' } #' ) -#' try(range(start = c(10, 15), end = 20)) -#' try(range(start = 20, end = 10)) +#' try(Range(start = c(10, 15), end = 20)) +#' try(Range(start = 20, end = 10)) #' -#' r <- range(start = 10, end = 20) +#' r <- Range(start = 10, end = 20) #' try(r@start <- 25) new_class <- function( name, @@ -322,8 +322,8 @@ str.S7_object <- function(object, ..., nest.lev = 0) { #' @returns An [S7 class][new_class]. #' @export #' @examples -#' foo <- new_class("foo") -#' S7_class(foo()) +#' Foo <- new_class("Foo") +#' S7_class(Foo()) S7_class <- function(object) { attr(object, "S7_class", exact = TRUE) } diff --git a/R/convert.R b/R/convert.R index c67c9718..a15721e9 100644 --- a/R/convert.R +++ b/R/convert.R @@ -41,36 +41,36 @@ #' is not possible. #' @export #' @examples -#' foo1 <- new_class("foo1", properties = list(x = class_integer)) -#' foo2 <- new_class("foo2", foo1, properties = list(y = class_double)) +#' Foo1 <- new_class("Foo1", properties = list(x = class_integer)) +#' Foo2 <- new_class("Foo2", Foo1, properties = list(y = class_double)) #' #' # Downcasting: S7 provides a default implementation for coercing an object #' # to one of its parent classes: -#' convert(foo2(x = 1L, y = 2), to = foo1) +#' convert(Foo2(x = 1L, y = 2), to = Foo1) #' #' # Upcasting: S7 also provides a default implementation for coercing an object #' # to one of its child classes: -#' convert(foo1(x = 1L), to = foo2) -#' convert(foo1(x = 1L), to = foo2, y = 2.5) # Set new property -#' convert(foo1(x = 1L), to = foo2, x = 2L, y = 2.5) # Override existing and set new +#' convert(Foo1(x = 1L), to = Foo2) +#' convert(Foo1(x = 1L), to = Foo2, y = 2.5) # Set new property +#' convert(Foo1(x = 1L), to = Foo2, x = 2L, y = 2.5) # Override existing and set new #' #' # For all other cases, you'll need to provide your own. -#' try(convert(foo1(x = 1L), to = class_integer)) +#' try(convert(Foo1(x = 1L), to = class_integer)) #' -#' method(convert, list(foo1, class_integer)) <- function(from, to) { +#' method(convert, list(Foo1, class_integer)) <- function(from, to) { #' from@x #' } -#' convert(foo1(x = 1L), to = class_integer) +#' convert(Foo1(x = 1L), to = class_integer) #' #' # Note that conversion does not respect inheritance so if we define a #' # convert method for integer to foo1 -#' method(convert, list(class_integer, foo1)) <- function(from, to) { -#' foo1(x = from) +#' method(convert, list(class_integer, Foo1)) <- function(from, to) { +#' Foo1(x = from) #' } -#' convert(1L, to = foo1) +#' convert(1L, to = Foo1) #' -#' # Converting to foo2 will still error -#' try(convert(1L, to = foo2)) +#' # Converting to Foo2 will still error +#' try(convert(1L, to = Foo2)) #' # This is probably not surprising because foo2 also needs some value #' # for `@y`, but it definitely makes dispatch for convert() special convert <- function(from, to, ...) { diff --git a/R/data.R b/R/data.R index 6243fdfa..22a38a36 100644 --- a/R/data.R +++ b/R/data.R @@ -11,8 +11,8 @@ #' invisibly. #' @export #' @examples -#' text <- new_class("text", parent = class_character) -#' y <- text(c(foo = "bar")) +#' Text <- new_class("Text", parent = class_character) +#' y <- Text(c(foo = "bar")) #' y #' S7_data(y) #' diff --git a/R/external-generic.R b/R/external-generic.R index 95ef67ee..b905846c 100644 --- a/R/external-generic.R +++ b/R/external-generic.R @@ -24,10 +24,10 @@ #' `S7_external_generic`. #' @export #' @examples -#' my_class <- new_class("my_class") +#' MyClass <- new_class("MyClass") #' #' your_generic <- new_external_generic("stats", "median", "x") -#' method(your_generic, my_class) <- function(x) "Hi!" +#' method(your_generic, MyClass) <- function(x) "Hi!" new_external_generic <- function(package, name, dispatch_args, version = NULL) { out <- list( package = package, diff --git a/R/inherits.R b/R/inherits.R index 0da413e4..c215fc6e 100644 --- a/R/inherits.R +++ b/R/inherits.R @@ -12,15 +12,15 @@ #' * `check_is_S7()` returns nothing; it's called for its side-effects. #' @export #' @examples -#' foo1 <- new_class("foo1") -#' foo2 <- new_class("foo2") +#' Foo1 <- new_class("Foo1") +#' Foo2 <- new_class("Foo2") #' -#' S7_inherits(foo1(), foo1) -#' check_is_S7(foo1()) -#' check_is_S7(foo1(), foo1) +#' S7_inherits(Foo1(), Foo1) +#' check_is_S7(Foo1()) +#' check_is_S7(Foo1(), Foo1) #' -#' S7_inherits(foo1(), foo2) -#' try(check_is_S7(foo1(), foo2)) +#' S7_inherits(Foo1(), Foo2) +#' try(check_is_S7(Foo1(), Foo2)) S7_inherits <- function(x, class = NULL) { if (!(is.null(class) || inherits(class, "S7_class"))) { stop("`class` must be an or NULL") diff --git a/R/method-introspect.R b/R/method-introspect.R index 40e073e7..ebdd07a1 100644 --- a/R/method-introspect.R +++ b/R/method-introspect.R @@ -69,14 +69,14 @@ method <- function(generic, class = NULL, object = NULL) { #' @return Nothing; this function is called for it's side effects. #' @export #' @examples -#' foo1 <- new_class("foo1") -#' foo2 <- new_class("foo2", foo1) +#' Foo1 <- new_class("Foo1") +#' Foo2 <- new_class("Foo2", Foo1) #' #' add <- new_generic("add", c("x", "y")) -#' method(add, list(foo2, foo1)) <- function(x, y) c(2, 1) -#' method(add, list(foo1, foo1)) <- function(x, y) c(1, 1) +#' method(add, list(Foo2, Foo1)) <- function(x, y) c(2, 1) +#' method(add, list(Foo1, Foo1)) <- function(x, y) c(1, 1) #' -#' method_explain(add, list(foo2, foo2)) +#' method_explain(add, list(Foo2, Foo2)) method_explain <- function(generic, class = NULL, object = NULL) { check_is_S7(generic, S7_generic) dispatch <- as_dispatch(generic, class = class, object = object) diff --git a/R/property.R b/R/property.R index e2cf4917..90fb6533 100644 --- a/R/property.R +++ b/R/property.R @@ -47,22 +47,22 @@ #' @export #' @examples #' # Simple properties store data inside an object -#' pizza <- new_class("pizza", properties = list( +#' Pizza <- new_class("Pizza", properties = list( #' slices = new_property(class_numeric, default = 10) #' )) -#' my_pizza <- pizza(slices = 6) +#' my_pizza <- Pizza(slices = 6) #' my_pizza@slices #' my_pizza@slices <- 5 #' my_pizza@slices #' -#' your_pizza <- pizza() +#' your_pizza <- Pizza() #' your_pizza@slices #' #' # Dynamic properties can compute on demand -#' clock <- new_class("clock", properties = list( +#' Clock <- new_class("Clock", properties = list( #' now = new_property(getter = function(self) Sys.time()) #' )) -#' my_clock <- clock() +#' my_clock <- Clock() #' my_clock@now; Sys.sleep(1) #' my_clock@now #' # This property is read only, because there is a 'getter' but not a 'setter' @@ -70,8 +70,8 @@ #' #' # Because the property is dynamic, it is not included as an #' # argument to the default constructor -#' try(clock(now = 10)) -#' args(clock) +#' try(Clock(now = 10)) +#' args(Clock) new_property <- function(class = class_any, getter = NULL, setter = NULL, @@ -176,12 +176,12 @@ prop_default <- function(prop, envir, package) { #' the modified object, invisibly. #' @export #' @examples -#' horse <- new_class("horse", properties = list( +#' Horse <- new_class("Horse", properties = list( #' name = class_character, #' colour = class_character, #' height = class_numeric #' )) -#' lexington <- horse(colour = "bay", height = 15, name = "Lex") +#' lexington <- Horse(colour = "bay", height = 15, name = "Lex") #' lexington@colour #' prop(lexington, "colour") #' @@ -352,8 +352,8 @@ prop_label <- function(object, name) { #' a single `TRUE` or `FALSE`. #' @export #' @examples -#' foo <- new_class("foo", properties = list(a = class_character, b = class_integer)) -#' f <- foo() +#' Foo <- new_class("Foo", properties = list(a = class_character, b = class_integer)) +#' f <- Foo() #' #' prop_names(f) #' prop_exists(f, "a") @@ -404,12 +404,12 @@ prop_exists <- function(object, name) { #' @returns A named list of property values. #' @export #' @examples -#' horse <- new_class("horse", properties = list( +#' Horse <- new_class("Horse", properties = list( #' name = class_character, #' colour = class_character, #' height = class_numeric #' )) -#' lexington <- horse(colour = "bay", height = 15, name = "Lex") +#' lexington <- Horse(colour = "bay", height = 15, name = "Lex") #' #' props(lexington) #' props(lexington) <- list(height = 14, name = "Lexington") diff --git a/R/super.R b/R/super.R index c1579afb..9793e161 100644 --- a/R/super.R +++ b/R/super.R @@ -26,18 +26,18 @@ #' For example, imagine that you have made a subclass of "integer": #' #' ```{r} -#' myint <- new_class("myint", parent = class_integer, package = NULL) +#' MyInt <- new_class("MyInt", parent = class_integer, package = NULL) #' ``` #' #' Now you go to write a custom print method: #' #' ```{r} -#' method(print, myint) <- function(x, ...) { -#' cat("") +#' method(print, MyInt) <- function(x, ...) { +#' cat("") #' print(super(x, to = class_integer)) #' } #' -#' myint(10L) +#' MyInt(10L) #' ``` #' #' This doesn't work because `print()` isn't an S7 generic so doesn't @@ -47,12 +47,12 @@ #' the underlying base object: #' #' ```{r} -#' method(print, myint) <- function(x, ...) { -#' cat("") +#' method(print, MyInt) <- function(x, ...) { +#' cat("") #' print(S7_data(x)) #' } #' -#' myint(10L) +#' MyInt(10L) #' ``` #' #' @param from An S7 object to cast. @@ -62,41 +62,41 @@ #' immediately to a generic. It has no other special behavior. #' @export #' @examples -#' foo1 <- new_class("foo1", properties = list(x = class_numeric, y = class_numeric)) -#' foo2 <- new_class("foo2", foo1, properties = list(z = class_numeric)) +#' Foo1 <- new_class("Foo1", properties = list(x = class_numeric, y = class_numeric)) +#' Foo2 <- new_class("Foo2", Foo1, properties = list(z = class_numeric)) #' #' total <- new_generic("total", "x") -#' method(total, foo1) <- function(x) x@x + x@y +#' method(total, Foo1) <- function(x) x@x + x@y #' #' # This won't work because it'll be stuck in an infinite loop: -#' method(total, foo2) <- function(x) total(x) + x@z +#' method(total, Foo2) <- function(x) total(x) + x@z #' #' # We could write -#' method(total, foo2) <- function(x) x@x + x@y + x@z +#' method(total, Foo2) <- function(x) x@x + x@y + x@z #' # but then we'd need to remember to update it if the implementation -#' # for total() ever changed. +#' # for total() ever changed. #' #' # So instead we use `super()` to call the method for the parent class: -#' method(total, foo2) <- function(x) total(super(x, to = foo1)) + x@z -#' total(foo2(1, 2, 3)) +#' method(total, Foo2) <- function(x) total(super(x, to = Foo1)) + x@z +#' total(Foo2(1, 2, 3)) #' #' # To see the difference between convert() and super() we need a #' # method that calls another generic #' #' bar1 <- new_generic("bar1", "x") -#' method(bar1, foo1) <- function(x) 1 -#' method(bar1, foo2) <- function(x) 2 +#' method(bar1, Foo1) <- function(x) 1 +#' method(bar1, Foo2) <- function(x) 2 #' #' bar2 <- new_generic("bar2", "x") -#' method(bar2, foo1) <- function(x) c(1, bar1(x)) -#' method(bar2, foo2) <- function(x) c(2, bar1(x)) +#' method(bar2, Foo1) <- function(x) c(1, bar1(x)) +#' method(bar2, Foo2) <- function(x) c(2, bar1(x)) #' -#' obj <- foo2(1, 2, 3) +#' obj <- Foo2(1, 2, 3) #' bar2(obj) #' # convert() affects every generic: -#' bar2(convert(obj, to = foo1)) +#' bar2(convert(obj, to = Foo1)) #' # super() only affects the _next_ call to a generic: -#' bar2(super(obj, to = foo1)) +#' bar2(super(obj, to = Foo1)) super <- function(from, to) { check_is_S7(from) diff --git a/S7.Rproj b/S7.Rproj index ef6fa310..552ad164 100644 --- a/S7.Rproj +++ b/S7.Rproj @@ -20,3 +20,5 @@ BuildType: Package PackageUseDevtools: Yes PackageInstallArgs: --no-multiarch --with-keep.source PackageRoxygenize: rd,collate,namespace + +MarkdownWrap: Sentence diff --git a/man/S4_register.Rd b/man/S4_register.Rd index df58ba91..abe5c2a1 100644 --- a/man/S4_register.Rd +++ b/man/S4_register.Rd @@ -23,9 +23,9 @@ methods::setGeneric("S4_generic", function(x) { standardGeneric("S4_generic") }) -foo <- new_class("foo") -S4_register(foo) -method(S4_generic, foo) <- function(x) "Hello" +Foo <- new_class("Foo") +S4_register(Foo) +method(S4_generic, Foo) <- function(x) "Hello" -S4_generic(foo()) +S4_generic(Foo()) } diff --git a/man/S7_class.Rd b/man/S7_class.Rd index 090ecd89..6867d64d 100644 --- a/man/S7_class.Rd +++ b/man/S7_class.Rd @@ -16,6 +16,6 @@ An \link[=new_class]{S7 class}. Given an S7 object, find it's class. } \examples{ -foo <- new_class("foo") -S7_class(foo()) +Foo <- new_class("Foo") +S7_class(Foo()) } diff --git a/man/S7_data.Rd b/man/S7_data.Rd index 5b295467..2f891cb2 100644 --- a/man/S7_data.Rd +++ b/man/S7_data.Rd @@ -28,8 +28,8 @@ to work with the underlying object, i.e. the S7 object stripped of class and properties. } \examples{ -text <- new_class("text", parent = class_character) -y <- text(c(foo = "bar")) +Text <- new_class("Text", parent = class_character) +y <- Text(c(foo = "bar")) y S7_data(y) diff --git a/man/S7_inherits.Rd b/man/S7_inherits.Rd index a312fa5e..ba9bb602 100644 --- a/man/S7_inherits.Rd +++ b/man/S7_inherits.Rd @@ -30,13 +30,13 @@ S7 object without testing for a specific class.} } } \examples{ -foo1 <- new_class("foo1") -foo2 <- new_class("foo2") +Foo1 <- new_class("Foo1") +Foo2 <- new_class("Foo2") -S7_inherits(foo1(), foo1) -check_is_S7(foo1()) -check_is_S7(foo1(), foo1) +S7_inherits(Foo1(), Foo1) +check_is_S7(Foo1()) +check_is_S7(Foo1(), Foo1) -S7_inherits(foo1(), foo2) -try(check_is_S7(foo1(), foo2)) +S7_inherits(Foo1(), Foo2) +try(check_is_S7(Foo1(), Foo2)) } diff --git a/man/convert.Rd b/man/convert.Rd index b43d36e5..b9a12988 100644 --- a/man/convert.Rd +++ b/man/convert.Rd @@ -52,36 +52,36 @@ functions/generics in S3, and to \code{as()}/\code{setAs()} in S4. } } \examples{ -foo1 <- new_class("foo1", properties = list(x = class_integer)) -foo2 <- new_class("foo2", foo1, properties = list(y = class_double)) +Foo1 <- new_class("Foo1", properties = list(x = class_integer)) +Foo2 <- new_class("Foo2", Foo1, properties = list(y = class_double)) # Downcasting: S7 provides a default implementation for coercing an object # to one of its parent classes: -convert(foo2(x = 1L, y = 2), to = foo1) +convert(Foo2(x = 1L, y = 2), to = Foo1) # Upcasting: S7 also provides a default implementation for coercing an object # to one of its child classes: -convert(foo1(x = 1L), to = foo2) -convert(foo1(x = 1L), to = foo2, y = 2.5) # Set new property -convert(foo1(x = 1L), to = foo2, x = 2L, y = 2.5) # Override existing and set new +convert(Foo1(x = 1L), to = Foo2) +convert(Foo1(x = 1L), to = Foo2, y = 2.5) # Set new property +convert(Foo1(x = 1L), to = Foo2, x = 2L, y = 2.5) # Override existing and set new # For all other cases, you'll need to provide your own. -try(convert(foo1(x = 1L), to = class_integer)) +try(convert(Foo1(x = 1L), to = class_integer)) -method(convert, list(foo1, class_integer)) <- function(from, to) { +method(convert, list(Foo1, class_integer)) <- function(from, to) { from@x } -convert(foo1(x = 1L), to = class_integer) +convert(Foo1(x = 1L), to = class_integer) # Note that conversion does not respect inheritance so if we define a # convert method for integer to foo1 -method(convert, list(class_integer, foo1)) <- function(from, to) { - foo1(x = from) +method(convert, list(class_integer, Foo1)) <- function(from, to) { + Foo1(x = from) } -convert(1L, to = foo1) +convert(1L, to = Foo1) -# Converting to foo2 will still error -try(convert(1L, to = foo2)) +# Converting to Foo2 will still error +try(convert(1L, to = Foo2)) # This is probably not surprising because foo2 also needs some value # for `@y`, but it definitely makes dispatch for convert() special } diff --git a/man/method_explain.Rd b/man/method_explain.Rd index 6b3edc8b..34b91a9c 100644 --- a/man/method_explain.Rd +++ b/man/method_explain.Rd @@ -33,12 +33,12 @@ to avoid ambiguity. } } \examples{ -foo1 <- new_class("foo1") -foo2 <- new_class("foo2", foo1) +Foo1 <- new_class("Foo1") +Foo2 <- new_class("Foo2", Foo1) add <- new_generic("add", c("x", "y")) -method(add, list(foo2, foo1)) <- function(x, y) c(2, 1) -method(add, list(foo1, foo1)) <- function(x, y) c(1, 1) +method(add, list(Foo2, Foo1)) <- function(x, y) c(2, 1) +method(add, list(Foo1, Foo1)) <- function(x, y) c(1, 1) -method_explain(add, list(foo2, foo2)) +method_explain(add, list(Foo2, Foo2)) } diff --git a/man/new_S3_class.Rd b/man/new_S3_class.Rd index cfb0dc75..2fe9f4d8 100644 --- a/man/new_S3_class.Rd +++ b/man/new_S3_class.Rd @@ -51,7 +51,7 @@ This is easy, and you can usually include the \code{new_S3_class()} call inline: \if{html}{\out{
}}\preformatted{method(my_generic, new_S3_class("factor")) <- function(x) "A factor" -new_class("my_class", properties = list(types = new_S3_class("factor"))) +new_class("MyClass", properties = list(types = new_S3_class("factor"))) new_union("character", new_S3_class("factor")) }\if{html}{\out{
}} } diff --git a/man/new_class.Rd b/man/new_class.Rd index 43a62718..ab260912 100644 --- a/man/new_class.Rd +++ b/man/new_class.Rd @@ -20,7 +20,7 @@ new_object(.parent, ...) \arguments{ \item{name}{The name of the class, as a string. The result of calling \code{new_class()} should always be assigned to a variable with this name, -i.e. \code{foo <- new_class("foo")}.} +i.e. \code{Foo <- new_class("Foo")}.} \item{parent}{The parent class to inherit behavior from. There are three options: @@ -86,13 +86,13 @@ Learn more in \code{vignette("classes-objects")} } \examples{ # Create an class that represents a range using a numeric start and end -range <- new_class("range", +Range <- new_class("Range", properties = list( start = class_numeric, end = class_numeric ) ) -r <- range(start = 10, end = 20) +r <- Range(start = 10, end = 20) r # get and set properties with @ r@start @@ -100,11 +100,11 @@ r@end <- 40 r@end # S7 automatically ensures that properties are of the declared types: -try(range(start = "hello", end = 20)) +try(Range(start = "hello", end = 20)) # But we might also want to use a validator to ensure that start and end # are length 1, and that start is < end -range <- new_class("range", +Range <- new_class("Range", properties = list( start = class_numeric, end = class_numeric @@ -119,9 +119,9 @@ range <- new_class("range", } } ) -try(range(start = c(10, 15), end = 20)) -try(range(start = 20, end = 10)) +try(Range(start = c(10, 15), end = 20)) +try(Range(start = 20, end = 10)) -r <- range(start = 10, end = 20) +r <- Range(start = 10, end = 20) try(r@start <- 25) } diff --git a/man/new_external_generic.Rd b/man/new_external_generic.Rd index d4b7c54d..2f7cadf0 100644 --- a/man/new_external_generic.Rd +++ b/man/new_external_generic.Rd @@ -36,8 +36,8 @@ Note that in tests, you'll need to explicitly call the generic from the external package with \code{pkg::generic()}. } \examples{ -my_class <- new_class("my_class") +MyClass <- new_class("MyClass") your_generic <- new_external_generic("stats", "median", "x") -method(your_generic, my_class) <- function(x) "Hi!" +method(your_generic, MyClass) <- function(x) "Hi!" } diff --git a/man/new_property.Rd b/man/new_property.Rd index 39f5b416..31063f8e 100644 --- a/man/new_property.Rd +++ b/man/new_property.Rd @@ -68,22 +68,22 @@ for more examples. } \examples{ # Simple properties store data inside an object -pizza <- new_class("pizza", properties = list( +Pizza <- new_class("Pizza", properties = list( slices = new_property(class_numeric, default = 10) )) -my_pizza <- pizza(slices = 6) +my_pizza <- Pizza(slices = 6) my_pizza@slices my_pizza@slices <- 5 my_pizza@slices -your_pizza <- pizza() +your_pizza <- Pizza() your_pizza@slices # Dynamic properties can compute on demand -clock <- new_class("clock", properties = list( +Clock <- new_class("Clock", properties = list( now = new_property(getter = function(self) Sys.time()) )) -my_clock <- clock() +my_clock <- Clock() my_clock@now; Sys.sleep(1) my_clock@now # This property is read only, because there is a 'getter' but not a 'setter' @@ -91,6 +91,6 @@ try(my_clock@now <- 10) # Because the property is dynamic, it is not included as an # argument to the default constructor -try(clock(now = 10)) -args(clock) +try(Clock(now = 10)) +args(Clock) } diff --git a/man/prop.Rd b/man/prop.Rd index 706754df..3eb9c7f1 100644 --- a/man/prop.Rd +++ b/man/prop.Rd @@ -39,12 +39,12 @@ a property. } } \examples{ -horse <- new_class("horse", properties = list( +Horse <- new_class("Horse", properties = list( name = class_character, colour = class_character, height = class_numeric )) -lexington <- horse(colour = "bay", height = 15, name = "Lex") +lexington <- Horse(colour = "bay", height = 15, name = "Lex") lexington@colour prop(lexington, "colour") diff --git a/man/prop_names.Rd b/man/prop_names.Rd index b364157a..d922adf1 100644 --- a/man/prop_names.Rd +++ b/man/prop_names.Rd @@ -26,8 +26,8 @@ a single \code{TRUE} or \code{FALSE}. } } \examples{ -foo <- new_class("foo", properties = list(a = class_character, b = class_integer)) -f <- foo() +Foo <- new_class("Foo", properties = list(a = class_character, b = class_integer)) +f <- Foo() prop_names(f) prop_exists(f, "a") diff --git a/man/props.Rd b/man/props.Rd index 31f73ec8..cbbbf0f2 100644 --- a/man/props.Rd +++ b/man/props.Rd @@ -36,12 +36,12 @@ object with new values for the specified properties. } } \examples{ -horse <- new_class("horse", properties = list( +Horse <- new_class("Horse", properties = list( name = class_character, colour = class_character, height = class_numeric )) -lexington <- horse(colour = "bay", height = 15, name = "Lex") +lexington <- Horse(colour = "bay", height = 15, name = "Lex") props(lexington) props(lexington) <- list(height = 14, name = "Lexington") diff --git a/man/super.Rd b/man/super.Rd index 98fad171..1989b2a2 100644 --- a/man/super.Rd +++ b/man/super.Rd @@ -42,18 +42,18 @@ understand and reason about. Note that you can't use \code{super()} in methods for an S3 generic. For example, imagine that you have made a subclass of "integer": -\if{html}{\out{
}}\preformatted{myint <- new_class("myint", parent = class_integer, package = NULL) +\if{html}{\out{
}}\preformatted{MyInt <- new_class("MyInt", parent = class_integer, package = NULL) }\if{html}{\out{
}} Now you go to write a custom print method: -\if{html}{\out{
}}\preformatted{method(print, myint) <- function(x, ...) \{ - cat("") +\if{html}{\out{
}}\preformatted{method(print, MyInt) <- function(x, ...) \{ + cat("") print(super(x, to = class_integer)) \} -myint(10L) -#> super(, ) +MyInt(10L) +#> super(, ) }\if{html}{\out{
}} This doesn't work because \code{print()} isn't an S7 generic so doesn't @@ -62,50 +62,50 @@ While you could resolve this problem with \code{\link[=NextMethod]{NextMethod()} implemented on top of S3), we instead recommend using \code{\link[=S7_data]{S7_data()}} to extract the underlying base object: -\if{html}{\out{
}}\preformatted{method(print, myint) <- function(x, ...) \{ - cat("") +\if{html}{\out{
}}\preformatted{method(print, MyInt) <- function(x, ...) \{ + cat("") print(S7_data(x)) \} -myint(10L) -#> [1] 10 +MyInt(10L) +#> [1] 10 }\if{html}{\out{
}} } } \examples{ -foo1 <- new_class("foo1", properties = list(x = class_numeric, y = class_numeric)) -foo2 <- new_class("foo2", foo1, properties = list(z = class_numeric)) +Foo1 <- new_class("Foo1", properties = list(x = class_numeric, y = class_numeric)) +Foo2 <- new_class("Foo2", Foo1, properties = list(z = class_numeric)) total <- new_generic("total", "x") -method(total, foo1) <- function(x) x@x + x@y +method(total, Foo1) <- function(x) x@x + x@y # This won't work because it'll be stuck in an infinite loop: -method(total, foo2) <- function(x) total(x) + x@z +method(total, Foo2) <- function(x) total(x) + x@z # We could write -method(total, foo2) <- function(x) x@x + x@y + x@z +method(total, Foo2) <- function(x) x@x + x@y + x@z # but then we'd need to remember to update it if the implementation -# for total() ever changed. +# for total() ever changed. # So instead we use `super()` to call the method for the parent class: -method(total, foo2) <- function(x) total(super(x, to = foo1)) + x@z -total(foo2(1, 2, 3)) +method(total, Foo2) <- function(x) total(super(x, to = Foo1)) + x@z +total(Foo2(1, 2, 3)) # To see the difference between convert() and super() we need a # method that calls another generic bar1 <- new_generic("bar1", "x") -method(bar1, foo1) <- function(x) 1 -method(bar1, foo2) <- function(x) 2 +method(bar1, Foo1) <- function(x) 1 +method(bar1, Foo2) <- function(x) 2 bar2 <- new_generic("bar2", "x") -method(bar2, foo1) <- function(x) c(1, bar1(x)) -method(bar2, foo2) <- function(x) c(2, bar1(x)) +method(bar2, Foo1) <- function(x) c(1, bar1(x)) +method(bar2, Foo2) <- function(x) c(2, bar1(x)) -obj <- foo2(1, 2, 3) +obj <- Foo2(1, 2, 3) bar2(obj) # convert() affects every generic: -bar2(convert(obj, to = foo1)) +bar2(convert(obj, to = Foo1)) # super() only affects the _next_ call to a generic: -bar2(super(obj, to = foo1)) +bar2(super(obj, to = Foo1)) } diff --git a/vignettes/S7.Rmd b/vignettes/S7.Rmd index c4b9bb21..7f6c32ad 100644 --- a/vignettes/S7.Rmd +++ b/vignettes/S7.Rmd @@ -34,11 +34,11 @@ There are two arguments that you'll use with almost every class: The following code defines a simple `dog` class with two properties: a character `name` and a numeric `age`. ```{r} -dog <- new_class("dog", properties = list( +Dog <- new_class("Dog", properties = list( name = class_character, age = class_numeric )) -dog +Dog ``` S7 provides a number of built-in definitions that allow you to refer to existing base types that are not S7 classes. @@ -49,7 +49,7 @@ This is important! That object represents the class and is what you use to construct instances of the class: ```{r} -lola <- dog(name = "Lola", age = 11) +lola <- Dog(name = "Lola", age = 11) lola ``` @@ -99,7 +99,7 @@ Like with `new_class()`, you should always assign the result of `new_generic()` Once you have a generic, you can register methods for specific classes with `method(generic, class) <- implementation`. ```{r} -method(speak, dog) <- function(x) { +method(speak, Dog) <- function(x) { "Woof" } ``` @@ -113,15 +113,15 @@ speak(lola) Let's define another class, this one for cats, and define another method for `speak()`: ```{r} -cat <- new_class("cat", properties = list( +Cat <- new_class("Cat", properties = list( name = class_character, age = class_double )) -method(speak, cat) <- function(x) { +method(speak, Cat) <- function(x) { "Meow" } -fluffy <- cat(name = "Fluffy", age = 5) +fluffy <- Cat(name = "Fluffy", age = 5) speak(fluffy) ``` @@ -137,7 +137,7 @@ The `cat` and `dog` classes share the same properties, so we could use a common We first define the parent class: ```{r} -pet <- new_class("pet", +Pet <- new_class("Pet", properties = list( name = class_character, age = class_numeric @@ -148,18 +148,18 @@ pet <- new_class("pet", Then use the `parent` argument to `new_class:` ```{r} -cat <- new_class("cat", parent = pet) -dog <- new_class("dog", parent = pet) +Cat <- new_class("Cat", parent = Pet) +Dog <- new_class("Dog", parent = Pet) -cat -dog +Cat +Dog ``` Because we have created new classes, we need to recreate the existing `lola` and `fluffy` objects: ```{r} -lola <- dog(name = "Lola", age = 11) -fluffy <- cat(name = "Fluffy", age = 5) +lola <- Dog(name = "Lola", age = 11) +fluffy <- Cat(name = "Fluffy", age = 5) ``` Method dispatch takes advantage of the hierarchy of parent classes: if a method is not defined for a class, it will try the method for the parent class, and so on until it finds a method or gives up with an error. @@ -167,13 +167,13 @@ This inheritance is a powerful mechanism for sharing code across classes. ```{r} describe <- new_generic("describe", "x") -method(describe, pet) <- function(x) { +method(describe, Pet) <- function(x) { paste0(x@name, " is ", x@age, " years old") } describe(lola) describe(fluffy) -method(describe, dog) <- function(x) { +method(describe, Dog) <- function(x) { paste0(x@name, " is a ", x@age, " year old dog") } describe(lola) @@ -187,12 +187,12 @@ method(describe, S7_object) <- function(x) { "An S7 object" } -cocktail <- new_class("cocktail", +Cocktail <- new_class("Cocktail", properties = list( ingredients = class_character ) ) -martini <- cocktail(ingredients = c("gin", "vermouth")) +martini <- Cocktail(ingredients = c("gin", "vermouth")) describe(martini) ``` @@ -205,7 +205,7 @@ describe And you can use `method()` to retrieve the implementation of one of those methods: ```{r} -method(describe, pet) +method(describe, Pet) ``` Learn more about method dispatch in `vignette("generics-methods")`. diff --git a/vignettes/classes-objects.Rmd b/vignettes/classes-objects.Rmd index 5c49026f..29e1c0d1 100644 --- a/vignettes/classes-objects.Rmd +++ b/vignettes/classes-objects.Rmd @@ -28,10 +28,10 @@ A validator is a function that takes the object (called `self`) and returns `NUL ### Basics -In the following example we create a range class that enforces that `@start` and `@end` are single numbers, and that `@start` is less than `@end`: +In the following example we create a `Range` class that enforces that `@start` and `@end` are single numbers, and that `@start` is less than `@end`: ```{r} -range <- new_class("range", +Range <- new_class("Range", properties = list( start = class_double, end = class_double @@ -62,17 +62,17 @@ As we'll discuss shortly, you can also perform validation on a per-property basi Objects are validated automatically when constructed and when any property is modified: ```{r, error = TRUE} -x <- range(1, 2:3) -x <- range(10, 1) +x <- Range(1, 2:3) +x <- Range(10, 1) -x <- range(1, 10) +x <- Range(1, 10) x@start <- 20 ``` You can also manually `validate()` an object if you use a low-level R function to bypass the usual checks and balances of `@`: ```{r, error = TRUE} -x <- range(1, 2) +x <- Range(1, 2) attr(x, "start") <- 3 validate(x) ``` @@ -87,13 +87,13 @@ shift <- function(x, shift) { x@end <- x@end + shift x } -shift(range(1, 10), 1) +shift(Range(1, 10), 1) ``` There's a problem if `shift` is larger than `@end` - `@start`: ```{r, error = TRUE} -shift(range(1, 10), 10) +shift(Range(1, 10), 10) ``` While the end result of `shift()` will be valid, an intermediate state is not. @@ -107,7 +107,7 @@ shift <- function(x, shift) { ) x } -shift(range(1, 10), 10) +shift(Range(1, 10), 10) ``` The object is still validated, but it's only validated once, after all the properties have been modified. @@ -119,7 +119,7 @@ This is a convenient shorthand for a call to `new_property()`. For example, the property definition of range above is shorthand for: ```{r} -range <- new_class("range", +Range <- new_class("Range", properties = list( start = new_property(class_double), end = new_property(class_double) @@ -137,13 +137,13 @@ For example, instead of validating the length of `start` and `end` in the valida ```{r, error = TRUE} prop_number <- new_property( - class = class_double, + class = class_double, validator = function(value) { if (length(value) != 1L) "must be length 1" } ) -range <- new_class("range", +Range <- new_class("Range", properties = list( start = prop_number, end = prop_number @@ -159,8 +159,8 @@ range <- new_class("range", } ) -range(start = c(1.5, 3.5)) -range(end = c(1.5, 3.5)) +Range(start = c(1.5, 3.5)) +Range(end = c(1.5, 3.5)) ``` Note that property validators shouldn't include the name of the property in validation messages as S7 will add it automatically. @@ -171,47 +171,48 @@ This makes it possible to use the same property definition for multiple properti The defaults of `new_class()` create an class that can be constructed with no arguments: ```{r} -empty <- new_class("empty", +Empty <- new_class("Empty", properties = list( x = class_double, y = class_character, z = class_logical )) -empty() +Empty() ``` The default values of the properties will be filled in with "empty" instances. You can instead provide your own defaults by using the `default` argument: ```{r} -empty <- new_class("empty", +Empty <- new_class("Empty", properties = list( x = new_property(class_numeric, default = 0), y = new_property(class_character, default = ""), z = new_property(class_logical, default = NA) ) ) -empty() +Empty() ``` -A quoted call becomes a standard function promise in the default constructor, -evaluated at the time the object is constructed. +A quoted call becomes a standard function promise in the default constructor, evaluated at the time the object is constructed. + ```{r} -stopwatch <- new_class("stopwatch", properties = list( +Stopwatch <- new_class("Stopwatch", properties = list( start_time = new_property( - class = class_POSIXct, + class = class_POSIXct, default = quote(Sys.time()) - ), + ), elapsed = new_property( getter = function(self) { difftime(Sys.time(), self@start_time, units = "secs") } ) )) -args(stopwatch) -round(stopwatch()@elapsed) -round(stopwatch(Sys.time() - 1)@elapsed) +args(Stopwatch) +round(Stopwatch()@elapsed) +round(Stopwatch(Sys.time() - 1)@elapsed) ``` + ### Computed properties It's sometimes useful to have a property that is computed on demand. @@ -219,7 +220,7 @@ For example, it'd be convenient to pretend that our range has a length, which is You can dynamically compute the value of a property by defining a `getter`: ```{r} -range <- new_class("range", +Range <- new_class("Range", properties = list( start = class_double, end = class_double, @@ -229,7 +230,7 @@ range <- new_class("range", ) ) -x <- range(start = 1, end = 10) +x <- Range(start = 1, end = 10) x ``` @@ -248,7 +249,7 @@ A `setter` is a function with arguments `self` and `value` that returns a modifi For example, we could extend the previous example to allow the `@length` to be set, by modifying the `@end` of the vector: ```{r} -range <- new_class("range", +Range <- new_class("Range", properties = list( start = class_double, end = class_double, @@ -263,7 +264,7 @@ range <- new_class("range", ) ) -x <- range(start = 1, end = 10) +x <- Range(start = 1, end = 10) x x@length <- 5 @@ -274,7 +275,7 @@ x `getter`, `setter`, `default`, and `validator` can be used to implement many common patterns of properties. -#### Deprecated properties +#### Deprecated properties A `setter` + `getter` can be used to to deprecate a property: @@ -305,28 +306,30 @@ hadley <- Person(firstName = "Hadley") hadley <- Person(first_name = "Hadley") # no warning -hadley@firstName +hadley@firstName -hadley@firstName <- "John" +hadley@firstName <- "John" hadley@first_name # no warning ``` - #### Required properties You can make a property required by the constructor either by: -- relying on the validator to error with the default value, or by -- setting the property default to a quoted error call. +- relying on the validator to error with the default value, or by +- setting the property default to a quoted error call. ```{r} Person <- new_class("Person", properties = list( - name = new_property(class_character, validator = function(value) { - if (length(value) != 1 || is.na(value) || value == "") - "must be a non-empty string" - })) -) + name = new_property( + class_character, + validator = function(value) { + if (length(value) != 1 || is.na(value) || value == "") + "must be a non-empty string" + } + ) +)) try(Person()) @@ -335,11 +338,11 @@ try(Person(1)) # class_character$validator() is also checked. Person("Alice") ``` - ```{r} Person <- new_class("Person", properties = list( - name = new_property(class_character, - default = quote(stop("@name is required"))) + name = new_property( + class_character, + default = quote(stop("@name is required"))) )) try(Person()) @@ -347,11 +350,9 @@ try(Person()) Person("Alice") ``` - #### Frozen properties -You can mark a property as read-only after construction by -providing a custom `setter`. +You can mark a property as read-only after construction by providing a custom `setter`. ```{r} Person <- new_class("Person", properties = list( @@ -371,13 +372,12 @@ person <- Person("1999-12-31") try(person@birth_date <- "2000-01-01") ``` - ## Constructors You can see the source code for a class's constructor by accessing the `constructor` property: ```{r} -range@constructor +Range@constructor ``` In most cases, S7's default constructor will be all you need. @@ -386,13 +386,15 @@ For example, for our range class, maybe we'd like to construct it from a vector To implement this we could do: ```{r} -range <- new_class("range", +Range <- new_class("Range", properties = list( start = class_numeric, end = class_numeric ), constructor = function(x) { - new_object(S7_object(), start = min(x, na.rm = TRUE), end = max(x, na.rm = TRUE)) + new_object(S7_object(), + start = min(x, na.rm = TRUE), + end = max(x, na.rm = TRUE)) } ) diff --git a/vignettes/compatibility.Rmd b/vignettes/compatibility.Rmd index f5382cca..cd4bc57d 100644 --- a/vignettes/compatibility.Rmd +++ b/vignettes/compatibility.Rmd @@ -49,14 +49,14 @@ All up, this means most usage of S7 with S3 will just work. You can also register a method for an S7 class and S3 generic without using S7, because all S7 objects have S3 classes, and S3 dispatch will operate on them normally. ```{r} -foo <- new_class("foo") -class(foo()) +Foo <- new_class("Foo") +class(Foo()) -mean.foo <- function(x, ...) { +mean.Foo <- function(x, ...) { "mean of foo" } -mean(foo()) +mean(Foo()) ``` ### Classes @@ -109,7 +109,7 @@ rle(1:10) Alternatively you could convert it to the most natural representation using S7: ```{r} -new_rle <- new_class("rle", properties = list( +rle <- new_class("rle", properties = list( lengths = class_integer, values = class_atomic )) @@ -118,7 +118,7 @@ new_rle <- new_class("rle", properties = list( To allow existing methods to work you'll need to override `$` to access properties instead of list elements: ```{r} -method(`$`, new_rle) <- prop +method(`$`, rle) <- prop rle(1:10) ``` @@ -143,15 +143,13 @@ In S4, they're handled at method dispatch time, so when you create `setUnion("u1 In S7, unions are handled at method registration time so that registering a method for a union is just short-hand for registering a method for each of the classes. ```{r} -class1 <- new_class("class1") -class2 <- new_class("class2") -union1 <- new_union(class1, class2) +Class1 <- new_class("Class1") +Class2 <- new_class("Class2") +Union1 <- new_union(Class1, Class2) foo <- new_generic("foo", "x") -method(foo, union1) <- function(x) "" +method(foo, Union1) <- function(x) "" 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. - -## diff --git a/vignettes/generics-methods.Rmd b/vignettes/generics-methods.Rmd index bac11933..ef7b9778 100644 --- a/vignettes/generics-methods.Rmd +++ b/vignettes/generics-methods.Rmd @@ -267,25 +267,25 @@ Multiple dispatch is heavily used in S4; we don't expect it to be heavily used i Let's take our speak example from `vignette("S7")` and extend it to teach our pets how to speak multiple languages: ```{r} -pet <- new_class("pet") -dog <- new_class("dog", pet) -cat <- new_class("cat", pet) +Pet <- new_class("Pet") +Dog <- new_class("Dog", Pet) +Cat <- new_class("Cat", Pet) -language <- new_class("language") -english <- new_class("english", language) -french <- new_class("french", language) +Language <- new_class("Language") +English <- new_class("English", Language) +French <- new_class("French", Language) speak <- new_generic("speak", c("x", "y")) -method(speak, list(dog, english)) <- function(x, y) "Woof" -method(speak, list(cat, english)) <- function(x, y) "Meow" -method(speak, list(dog, french)) <- function(x, y) "Ouaf Ouaf" -method(speak, list(cat, french)) <- function(x, y) "Miaou" +method(speak, list(Dog, English)) <- function(x, y) "Woof" +method(speak, list(Cat, English)) <- function(x, y) "Meow" +method(speak, list(Dog, French)) <- function(x, y) "Ouaf Ouaf" +method(speak, list(Cat, French)) <- function(x, y) "Miaou" -speak(cat(), english()) -speak(dog(), french()) +speak(Cat(), English()) +speak(Dog(), French()) # This example was originally inspired by blog.klipse.tech/javascript/2021/10/03/multimethod.html -# which has unfortunately since disappeaed. +# which has unfortunately since disappeared. ``` ### Special "classes" diff --git a/vignettes/performance.Rmd b/vignettes/performance.Rmd index e44cb5d4..8ded2b8e 100644 --- a/vignettes/performance.Rmd +++ b/vignettes/performance.Rmd @@ -21,38 +21,38 @@ library(S7) The dispatch performance should be roughly on par with S3 and S4, though as this is implemented in a package there is some overhead due to `.Call` vs `.Primitive`. ```{r performance, cache = FALSE} -text <- new_class("text", parent = class_character) -number <- new_class("number", parent = class_double) +Text <- new_class("Text", parent = class_character) +Number <- new_class("Number", parent = class_double) -x <- text("hi") -y <- number(1) +x <- Text("hi") +y <- Number(1) foo_S7 <- new_generic("foo_S7", "x") -method(foo_S7, text) <- function(x, ...) paste0(x, "-foo") +method(foo_S7, Text) <- function(x, ...) paste0(x, "-foo") foo_S3 <- function(x, ...) { UseMethod("foo_S3") } -foo_S3.text <- function(x, ...) { +foo_S3.Text <- function(x, ...) { paste0(x, "-foo") } library(methods) -setOldClass(c("number", "numeric", "S7_object")) -setOldClass(c("text", "character", "S7_object")) +setOldClass(c("Number", "numeric", "S7_object")) +setOldClass(c("Text", "character", "S7_object")) setGeneric("foo_S4", function(x, ...) standardGeneric("foo_S4")) -setMethod("foo_S4", c("text"), function(x, ...) paste0(x, "-foo")) +setMethod("foo_S4", c("Text"), function(x, ...) paste0(x, "-foo")) # Measure performance of single dispatch bench::mark(foo_S7(x), foo_S3(x), foo_S4(x)) bar_S7 <- new_generic("bar_S7", c("x", "y")) -method(bar_S7, list(text, number)) <- function(x, y, ...) paste0(x, "-", y, "-bar") +method(bar_S7, list(Text, Number)) <- function(x, y, ...) paste0(x, "-", y, "-bar") setGeneric("bar_S4", function(x, y, ...) standardGeneric("bar_S4")) -setMethod("bar_S4", c("text", "number"), function(x, y, ...) paste0(x, "-", y, "-bar")) +setMethod("bar_S4", c("Text", "Number"), function(x, y, ...) paste0(x, "-", y, "-bar")) # Measure performance of double dispatch bench::mark(bar_S7(x, y), bar_S4(x, y)) @@ -80,8 +80,8 @@ bench::press( class_nchar = c(15, 100), { # Construct a class hierarchy with that number of classes - text <- new_class("text", parent = class_character) - parent <- text + Text <- new_class("Text", parent = class_character) + parent <- Text classes <- gen_character(num_classes, min = class_nchar, max = class_nchar) env <- new.env() for (x in classes) { @@ -119,8 +119,8 @@ bench::press( class_nchar = c(15, 100), { # Construct a class hierarchy with that number of classes - text <- new_class("text", parent = class_character) - parent <- text + Text <- new_class("Text", parent = class_character) + parent <- Text classes <- gen_character(num_classes, min = class_nchar, max = class_nchar) env <- new.env() for (x in classes) {