2012-08-23 11 views
9

¿Cuál es una buena forma de definir una función de propósito general que debería tener implementaciones para las clases S3 y S4? He estado usando algo como esto:Combinación de métodos S4 y S3 en una sola función

setGeneric("myfun", function(x, ...){ 
    standardGeneric("myfun"); 
}); 

setMethod("myfun", "ANY", function(x, ...) { 
    if(!isS4(x)) { 
     return(UseMethod("myfun")); 
    } 
    stop("No implementation found for class: ", class(x)); 
}); 

Esto tiene éxito:

myfun.bar <- function(x, ...){ 
    return("Object of class bar successfully dispatched."); 
} 
object <- structure(123, class=c("foo", "bar")); 
myfun(object) 

¿Hay alguna manera movimiento "nativo" para lograr esto? Sé que podemos definir métodos S4 para clases S3 usando setOldClass, sin embargo, de esta manera perdemos el envío del método S3 en caso de que un objeto tenga múltiples clases. P.ej. (En una sesión limpia):

setGeneric("myfun", function(x, ...){ 
    standardGeneric("myfun"); 
}); 

setOldClass("bar") 
setMethod("myfun", "bar", function(x, ...){ 
    return("Object of class bar successfully dispatched."); 
}); 

object <- structure(123, class=c("foo", "bar")); 
myfun(object) 

Esta falla porque la segunda clase de object, en este caso bar, se ignora. Probablemente podríamos solucionar esto definiendo la herencia formal de S4 entre foo y bar, pero para mi aplicación preferiría que myfun.bar fuera de la caja en objetos S3 con una clase bar.

De cualquier manera, las cosas se están volviendo complicadas, y supongo que este es un problema común, entonces ¿hay probablemente mejores formas de hacerlo?

+0

Vea también http://stackoverflow.com/questions/12709933/adding-s4-dispatch-to-base-r-s3-generic para el caso especial de agregar envío S4 a un genérico S3 en la base R. –

Respuesta

13

La sección "Métodos para funciones genéricas S3" de? Methods sugiere un S3 genérico, un método de estilo S3 para clases S4 y el método S4 en sí mismo.

setClass("A")     # define a class 

f3 <- function(x, ...)   # S3 generic, for S3 dispatch  
    UseMethod("f3") 
setGeneric("f3")     # S4 generic, for S4 dispatch, default is S3 generic 
f3.A <- function(x, ...) {}  # S3 method for S4 class 
setMethod("f3", "A", f3.A)  # S4 method for S4 class 

El genérico S3 es necesario para despachar clases S3.

setGeneric() establece el f3 (es decir, el S3 genérico) como el valor predeterminado, y f3, ANY-method es en realidad el S3 genérico. Como 'ANY' está en (algo así como) la raíz de la jerarquía de clases, cualquier objeto (por ejemplo, objetos S3) para el que no exista un método S4 termina en el genérico S3.

La definición de un S3 genérico para una clase S4 se describe en la página de ayuda? Métodos. Creo, aproximadamente, que S3 no sabe acerca de los métodos S4, por lo que si uno invoca el genérico S3 (por ejemplo, porque uno está en un espacio de nombre de paquete donde el paquete conoce el S3 f3 pero no el S4 f3) el genérico f3 no encontraría el método S4. Solo soy el mensajero.

+0

Entonces ¿significa eso que los métodos S4 se buscan primero sobre la base de sus firmas y, si no se produce una coincidencia, se envían los métodos S3? –

+0

@DWin sí, eso es correcto –

+0

¿Podría explicarnos por qué se necesitan la primera y la última línea? – Jeroen

Cuestiones relacionadas