I'm attempting to override base (non-S3) methods to provide colnames methods for a custom R object. I want to do this with S3 not S4.
For the colnames accessor, this can be achieved by setting the base function to be the default method, then providing a method for my class:
colnames <- function(x, ...) UseMethod("colnames")
colnames.default <- base::colnames
colnames.myclass <- function(x, ...) {
# some code here
}
However, how would one override the setter method. I would hope something like this should work?
"colnames<-" <- function(x, value) UseMethod("colnames<-")
"colnames<-.default" <- "base::colnames<-"
"colnames<-.myclass" <- function(x, value) {
print("Setting colnames for myclass")
# Some code
}
However, this seems to fail to call the base function correctly for a regular matrix:
> test <- matrix(1:10, 5)
> colnames(test) <- c("a", "b")
Error in UseMethod("colnames<-") :
no applicable method for 'colnames<-' applied to an object of class "c('matrix', 'integer', 'numeric')"
You set colnames<-.default to a character string (i.e. not a function). That's not going to work.
"colnames<-.default" <- "base::colnames<-"
Use backticks to reference objects with non-syntactic names.
`colnames<-.default` <- base::`colnames<-`
Related
With the S3 object system, in a generic method you can delegate to the next method in a class hierarchy using the NextMethod() function. When Wickham describes this system at http://adv-r.had.co.nz/S3.html, he uses NextMethod() without any arguments in his example:
baz <- function(x) UseMethod("baz", x)
baz.C <- function(x) c("C", NextMethod())
I've always used NextMethod() without argument in my own code as well.
I just noticed that [.Date uses an explicit argument:
> `[.Date`
function (x, ..., drop = TRUE)
{
cl <- oldClass(x)
class(x) <- NULL
val <- NextMethod("[")
class(val) <- cl
val
}
The documentation for ?NextMethod says the following:
Normally 'NextMethod' is used with only one argument, 'generic'
In terms of performance, is calling NextMethod("generic") faster than NextMethod()? Is there any other reason to prefer one usage over the other?
How do I define a method for a list of objects of the same class?
Eg.
foo <- letters[1:5]
foo2 <- letters[6:10]
class(foo) <- "abc"
class(foo2) <- "abc"
new_method <- function(...) {UseMethod("new_method", ...)}
new_method.abc <- function(...) {do.call("c", list(...))}
# use results in error
new_method(foo,foo2)
Error in new_method(foo, foo2) : '...' used in an incorrect context
Here I want ... to be an arbitrary length list of objects all of which have the same class and I want to do something with them (combine them, specific to my real class's use case).
It makes sense to me that ... doesn't have a class that can be sent to method dispatch; but a simple re-write also doesn't work since new_method.list doesn't / shouldn't exist
new_method <- function(...) {UseMethod("new_method", list(...))}
new_method(foo,foo2)
Error in UseMethod("new_method", list(...)) :
no applicable method for 'new_method' applied to an object of class "list"
How can I implement the generic function names for my S3 class so I can "set" the names of my object.
To retrieve the names I simply implemented it as:
names.myobject <- function(x, ...){
x$y
}
and then I can do:
names(myobject)
But I can't use it to set the names in the form of:
names(myobject) <- "a"
I'm thinking to something like:
names.myobject <- function(x, newname){
x$y <- newnames
}
How can implement the "set" form of names?
Figure out the signatures of the generics from the functions; the 'setter' is names<-.
> names
function (x) .Primitive("names")
> `names<-`
function (x, value) .Primitive("names<-")
names and names<- are so-called primitive functions, with method dispatch implemented in C, so the usual indication that you're working with an S3 generic (UseMethod("foo") in the body of the generic) is not present.
Implement methods following the pattern generic.class = function.... Remember that the return value of the setter method needs to be the object that you've updated
names.myobject <- function(x) x$y
`names<-.myobject` <- function(x, value) { x$y = value; x }
I would like to know if a given object has a particular method.
For example, suppose I want to know whether my mystery object has a specific print method. From reading ?methods, I try something like this:
has.print <- function (mysteryObject) {
'print' %in% attr(methods(class=class(mysteryObject)), 'info')$generic
}
m <- lm(Sepal.Length ~ Species, iris)
class(m) # 'lm'
has.print(m)
This is fine if mysteryObject has just one class. If it has multiple, there are problems in methods. I can get around this by using class(mysteryObject)[1], so that (for example)
library(data.table)
class(test) # data.table, data.frame
test <- data.table(iris)
has.print(test) # TRUE since there's a print.data.table
However, if I have something with multiple classes but the first does not have a print method, this returns false. Example:
mlm <- lm(cbind(Petal.Length, Petal.Width) ~ Species, iris)
class(mlm) # 'mlm', 'lm'. Note there is no print.mlm but there's a print.lm
has.print(mlm) # FALSE
This returns FALSE as there is no print.mlm. However, there is a print.lm, that is used instead, so I would like this to return TRUE.
Speaking as someone who knows very little about S3, S4, etc, is there a "proper" way to see if an object has a 'print' method on any of its classes? Ideally this works for both S3 and S4 objects, though I do not know what this means.
I can vectorise my methods(class=...) over class(mysteryObject), but I bet there's a more appropriate way to do it...
Apply methods on every class, unlist and search for "print":
has.print <- function(object) {
"print" %in%
unlist(
lapply(
class(object),
function(x) attr(methods(class = x), "info")$generic)
)
}
It is possible to start from the other side (searching for a class in all
generic print functions):
has.print <- function(object) {
any( sprintf("print.%s", class(object)) %in%
rownames(attr(methods(generic.function = "print"), "info")))
}
To find the method:
which.print <- function(object) {
print_methods <- rownames(attr(methods(generic.function = "print"), "info"))
print_methods[print_methods %in% sprintf("print.%s", class(object))]
}
# > which.print(mlm)
# [1] "print.lm"
S4
S4 classes are "printed" with show method. If no specialized method exists the showDefault is called. Function showMethods will show if there is any specialized show:
For example:
library(Matrix)
showMethods(f = "show", class = "denseMatrix")
#> Function: show (package methods)
#> object="denseMatrix"
showDefault is also calling print for non S4 members.
Imagine I created a class "stem" with some S3 methods. i need to compare a number of stem objects with a function like
comp.default = function(smpc = x){
message("I am default")
}
comp <- function(x) UseMethod("comp", x)
comp.stem = function(listOfStemObjects, print = TRUE, more args){ a bunch of things}
comp(list(stem1, stem2))
The function doesn't recognize the class because the first argument is of class "list" and not stem. Ideally I would like to pass a variable number of objects stem1, stem2,..
Any help?
Thanks in advance, marco
comp <- function(x, ...) UseMethod("comp")
comp.stem <- function(x, ...)
{
lst <- list(...)
for(i in seq_along(lst))
# do stuff with each additional object passed in
}
comp(stem1, stem2)