rr-s4

How to set an S4 method for 2+ classes?


I would like to set a method for 2+ classes, and also enable to pass additional argument.

The 2 classes :

# Classes
methods::setClass(
  Class = "A",
  slots = list(
    x = "character"
  )
)
methods::setClass(
  Class = "B",
  slots = list(
    x = "character"
  )
)

The method dispatch should be done only for one object (the object argument, which is set as the signature of the generic). The Generic :

# Generic
methods::setGeneric(
  "method1",
  def = function(object, additionalArg) base::standardGeneric("method1"),
  signature = "object"
)

The method should make use of the object slot, and also the additionalArg if it is passed. The Method :

# Method
methods::setMethod(
  "method1",
  signature = c(
    "A",
    "B"
  ),
  definition = function(object, additionalArg = NULL) {
    print(glue::glue("Object slot : {object@x}"))
    if (!is.null(additionalArg)) {
      print(glue::glue("Additional argument : {additionalArg}"))
    }
  }
)

However, the setMethod fails, even though the signature is set to the object argument, and both the generic and the method implementation for objects of class A and B contain the object and additionalArg arguments.

The error :

Error in matchSignature(signature, fdef) : 
  more elements in the method signature (2) than in the generic signature (1) for function ‘method1’

Edit: This happens also with the generic and the method having only "object" as argument, so it is not due to having more than 1 argument.


Solution

  • You can only set one method at a time. If you make two separate calls to setMethod (one for A and one for B), using the same function definition each time, then you will have no problem.

    Alternatively, you can call setClassUnion to create a class union of A and B, and use that class union in your call to setMethod.