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

Viewed 128

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.

1 Answers

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.

Related