Use one Class of an Object with Multiple - r

This is a general question motivated by a specific event.
When an object holds multiple classes, each with different generic actions, how can I specify to use "this" class, rather than "that" class?
The example code here is bundled with geepack.
library(stargazer)
library(geepack)
data(dietox)
dietox$Cu <- as.factor(dietox$Cu)
mf <- formula(Weight~Cu*(Time+I(Time^2)+I(Time^3)))
gee0 <- glm(mf, data = dietox, family = poisson("identity")) # a wrong model
gee1 <- geeglm(mf, data=dietox, id=Pig, family=poisson("identity"),corstr="ar1")
class(gee0)
class(gee1)
summary(gee0)
summary(gee1)
stargazer(gee0, type = "text")
stargazer(gee1, type = "text")
I'd like to work with the "glm" class object, not the "geeglm" class object.
#Richard Scriven: I'd just like to pull the results out into a stargazer(...) report. Thanks for the clarifying question.

The class system that uses the class(foo) attribute is not strongly typed. The class vector is used by R to determine which methods to use when that object is passed to a generic like print. For example, if you were to call print(gee1), R would first search for a function called print.geeglm which, in this case, it would find in the package geepack, and R calls that function with the arguments supplied to print().
If R did not find a function called print.geeglm, it would then search for print.gee, then print.glm, then print.default.
So in short, gee1 does not contain 3 objects with different classes, it is a single object with a class vector that informs R where to look for generic methods.
To make things slightly more confusing R has multiple type systems and the class vetcor is used by the S3 type system. A google search for "R s3 class" will get you lots more info on R's class system.

Related

How to define an S3 generic with the same name as a primitive function?

I have a class myclass in an R package for which I would like to define a method as.raw, so of the same name as the primitive function as.raw(). If constructor, generic and method are defined as follows...
new_obj <- function(n) structure(n, class = "myclass") # constructor
as.raw <- function(obj) UseMethod("as.raw") # generic
as.raw.myclass <- function(obj) obj + 1 # method (dummy example here)
... then R CMD check leads to:
Warning: declared S3 method 'as.raw.myclass' not found
See section ‘Generic functions and methods’ in the ‘Writing R
Extensions’ manual.
If the generic is as_raw instead of as.raw, then there's no problem, so I assume this comes from the fact that the primitive function as.raw already exists. Is it possible to 'overload' as.raw by defining it as a generic (or would one necessarily need to use a different name?)?
Update: NAMESPACE contains
export("as.raw") # export the generic
S3method("as.raw", "myclass") # export the method
This seems somewhat related, but dimnames there is a generic and so there is a solution (just don't define your own generic), whereas above it is unclear (to me) what the solution is.
The problem here appears to be that as.raw is a primitive function (is.primitive(as.raw)). From the ?setGeneric help page, it says
A number of the basic R functions are specially implemented as primitive functions, to be evaluated directly in the underlying C code rather than by evaluating an R language definition. Most have implicit generics (see implicitGeneric), and become generic as soon as methods (including group methods) are defined on them.
And according to the ?InternalMethods help page, as.raw is one of these primitive generics. So in this case, you just need to export the S3method. And you want to make sure your function signature matches the signature of the existing primitive function.
So if I have the following R code
new_obj <- function(n) structure(n, class = "myclass")
as.raw.myclass <- function(x) x + 1
and a NAMESPACE file of
S3method(as.raw,myclass)
export(new_obj)
Then this passes the package checks for me (on R 4.0.2). And I can run the code with
as.raw(new_obj(4))
# [1] 5
# attr(,"class")
# [1] "myclass"
So in this particular case, you need to leave the as.raw <- function(obj) UseMethod("as.raw") part out.

How to see available parameters and documentation for a class method in R?

How can we see all available parameters (or view documentation more generally) for a class method?
For example, if we look at arguments for print()
?print
x
an object used to select a method.
...
further arguments passed to or from other methods.
quote
logical, indicating whether or not strings should be printed with surrounding quotes.
-- leaving others out for brevity --
useSource
logical indicating if internally stored source should be used for printing when present, e.g., if options(keep.source = TRUE) has been in use.
Note that we do not see any documentation for the parameter max_n.
Now suppose we call print() on something of class xml_nodes, e.g:
library(rvest)
library(dplyr)
# Generate an object of class xml_nodes
a <- rep("<p></p>", 30) %>%
paste0(collapse="") %>%
read_html %>%
html_nodes("p")
class(a)
# [1] "xml_nodeset"
a is of class xml_nodeset, and if we call print(a), it prints only 20 results, and that's because (I think) the xml_nodeset class is configured such that when print is called on it, it will only return 20 results. (the '20' number can be changed via the max_n parameter).
How do we find the specific documentation for how print will behave when called on the object of class xml_nodeset? (preferably via RStudio/manuals)
Note that the example above is just a random example, I would like to find a general way of finding documentation for all class methods
You can see all the "special" version of print by running methods(print). These versions are typically in the form <function name>.<class name>. Many listed there have astericks which means they are not directly exported from the packages where they are defined. If they have documentation, you can access it via ?print.rle for example. In this case there is no documentation for the print.xml_nodeset function. But you can look at it if you do getAnywhere(print.xml_nodeset) or if you happened to know it was from the xml2 namespace, you could do xml2:::print.xml_nodeset (with three colons).
There's also the sloop package which can tell you which S3 method will be called for a given invocation. For example
sloop::s3_dispatch(print(a))
=> print.xml_nodeset
* print.default
You could file an issue with the package maintainer asking to provide documentation for the function, but otherwise R can't really give you documentation if the author did not include it.

dollar suggestions method in S3

I'm making right now a R package and I have to chose between returning lists and an object with S3 attributes.
The good thing, as for the lists, is that it's very easy to use for beginners, due to the dollar sign making all the elements easy to find.
The bad thing, is that it removes direct inheritance (I'd like to return a ts object with some additional informations).
The alternative would be to set the dollar for my S3 class, like this example :
object <- 1
class(object) <- "MyClass"
attr(object,"MyAttribute") <- "This is a secret"
`$.MyClass` <- function(x,name) attr(object,name)
object$MyAttribute
However, I have 2 questions about this :
Where to set the dollar partial matching function for the user to see "MyAttribute" as a valid choice in rstudio ?
Besides, is that a fine practice to do so or should I keep on using simple lists
Thanks
I don’t think RStudio currently allows this kind of customisation. In other R terminals you could play with rcompgen to generate completions but IIRC RStudio does its own thing.
That said, your question seems to be based on a false dichotomy:
Besides, is that a fine practice to do so or should I keep on using simple lists
You don’t need to choose either–or. In fact, it’s common to have lists with S3 classes, and it is not common to use attributes to store S3 information that are then accessed via $. Just make your class a list:
object = structure(
list(value = 1, MyAttribute = "This is a secret"),
class = "MyClass"
)
object$MyAttribute

How to overload S4 slot selector `#` to be a generic function

I am trying to turn the # operator in R into a generic function for the S3 system.
Based on the chapter in Writing R extensions: adding new generic I tried implementing the generic for # like so:
`#` <- function(object, name) UseMethod("#")
`#.default` <- function(object, name) base::`#`(object, name)
However this doesn't seem to work as it breaks the # for the S4 methods. I am using Matrix package as an example of S4 instance:
Matrix::Matrix(1:4, nrow=2, ncol=2)#Dim
Error in #.default(Matrix::Matrix(1:4, nrow = 2, ncol = 2), Dim) :
no slot of name "name" for this object of class "dgeMatrix"
How to implement a generic # so it correctly dispatches in the case of S4 classes?
EDIT
Also interested in opinions about why it might not be a good idea?
R's documentation is somewhat confusing as to whether # is already a generic or not: the help page for # says it is, but it isn't listed on the internalGenerics page.
The # operator has specific behaviour as well as (perhaps) being a generic. From the help page for #: "It is checked that object is an S4 object (see isS4), and it is an error to attempt to use # on any other object." That would appear to rule out writing methods for S3 classes, though the documentation is unclear if this check happens before method dispatch (if there is any) or after (whence it could be skipped if you supplied a specific method for some S3 class).
You can implement what you want by completely redefining what # is, along the line of the suggestion in comments:
`#.default` <- function(e1,e2) slot(e1,substitute(e2))
but there are two reasons not to do this:
1) As soon as someone loads your package, it supersedes the normal # function, so if people call it with other S4 objects, they are getting your version rather than the R base version.
2) This version is considerably less efficient than the internal one, and because of (1) you have just forced your users to use it (unless they use the cumbersome construction base::"#"(e1,e2)). Efficiency may not matter to your use case, but it may matter to your users' other code that uses S4.
Practically, a reasonable compromise might be to define your own binary operator %#%, and have the default method call #. That is,
`%#%` <- function(e1,e2) slot(e1,substitute(e2))
setGeneric("%#%")
This is called in practice as follows:
> setClass("testClass",slots=c(a="character")) -> testClass
> x <- testClass(a="cheese")
> x %#% a
[1] "cheese"

Creating S3 methods in R

for an advanced programming in R class we've been asked to create a package. The package is to include a function, "lad", a dataset, "area", and 3 methods, "print.lad", "coef.lad", and "predict.lad".
I have my "lad" function saved, and when building/requiring my package the function runs just fine. However, I'm a bit confused on the usage of setMethod.
For example, I created a new .R script titled "print.lad" in my "R" folder within the package. This method is to write the coefficient vector from the output of "lad" to the console. We've been instructed to make the output of "lad" a list of type "lad" with "coefficients" being the first in the list.
We've never gone over methods in class, so I had to look around on the internet for help. After the information/parameters/etc section, my code for "print.lad" looks like this:
setMethod("print", "lad", function(object){
print(object$coefficients)
} )
I can see that this isn't correct, but I'm also puzzled as to how to apply this setMethod function. I don't wish for someone to give me a working chunk of code outright, but an example of the application of setMethod and a bit of insight would be greatly appreciated. Thank you!
Create an object:
object <- list(coefficients = c("a" = 3, "b" = 4))
Assign the object a class:
class(object) <- "lad"
S3 methods have the form function.class. To define a "print" method:
print.lad <- function(object) {
print("Here are the coefficients:")
print(object$coefficients)
}
S3 methods are then automatically dispatched based on the object's class
print(object)
# [1] "Here are the coefficients:"
# a b
# 3 4
As an aside, I think I read somewhere that you should define print methods using cat instead of print because it's easier to control and nest, but I can't seem to find the source for that. For small cases, it shouldn't matter much.

Resources