2012-08-24 12 views
7

Relacionados con la pregunta this, pero ligeramente diferentes y, con suerte, más claros.Envío de estilo S3 para objetos S3 utilizando las definiciones de métodos formales

Estoy buscando clean forma de registrar formalmente los métodos para las clases S4 y S3, pero sin depender del terrible esquema de denominación de puntos S3 para el envío. Un ejemplo:

setClass("foo"); 
setClass("bar"); 

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

setMethod("test", "bar", function(x, ...){ 
    return("success (bar)."); 
}); 

obj1 <- 123; 
class(obj1) <- "bar"; 
test(obj1); 

Este ejemplo muestra cómo se puede registrar un método test para los objetos de la clase S3 bar, sin la necesidad de nombrar la función test.bar, que es grande. Sin embargo, la limitación es que si registramos los métodos de esta manera, solo se enviarán a la primera clase S3 del objeto. Por ejemplo:

obj2 <- 123; 
class(obj2) <- c("foo", "bar"); 
test(obj2); 

Esto no funciona, ya que el método S4 despacho sólo intentará clase foo y sus superclases. ¿Cómo podría extenderse este ejemplo para que seleccione automáticamente el método test para bar cuando no se encontró el método apropiado para foo? P.ej. Envío de estilo S3 pero sin tener que volver a nombrar todo test.foo y test.bar?

Así que en resumen: cómo crear una función genérica que utiliza el envío de métodos formales, pero también recurrir a la segunda, tercera, etc. clase de un objeto para objetos S3 con múltiples clases.

Respuesta

2

Se puede escribir un método

test = function(x, ...) UseMethod("test") 

setGeneric("test") 

.redispatch = function(x, ...) 
{ 
    if (is.object(x) && !isS4(x) && length(class(x)) != 1L) { 
     class(x) = class(x)[-1] 
     callGeneric(x, ...) 
    } else callNextMethod(x, ...) 
} 

setMethod(test, "ANY", .redispatch) 

Pero yo personalmente no mezclar S3 y S4 de esta manera.

+0

Sí, he estado haciendo algo similar; sin embargo, el hecho de que realmente esté cambiando el atributo de clase de x a lo largo del camino puede tener efectos secundarios indeseables ... ¿Hay alguna manera de enviarlo al siguiente método sin modificar el objeto en sí? – Jeroen

+0

No tengo una respuesta para usted; Creo que el método S4 para 'bar' que trabaja en una 'barra' de la clase S3 es un accidente de implementación, y estás construyendo una estructura compleja sobre cimientos muy inestables. –

3

?setOldClass dará la respuesta:

setOldClass(c("foo", "bar")) 

setGeneric("test", function(x, ...)standardGeneric("test")) 
setMethod("test", "bar", function(x, ...)return("success (bar).")) 
+0

Así que esto es exactamente * no * lo que quiero. Requiere una herencia formal entre las clases "foo" y "bar", lo que podría no ser el caso. Quiero que funcione para cualquier objeto arbitrario con class = [x, "bar"] para x = cualquier cosa, sin tener que declarar herencia entre x y "bar" para cada posible clase x. Supongamos que alguien más ha creado un objeto con clases ["zoo", "bar"], luego la función 'test()' debe ser lo suficientemente inteligente como para seleccionar el método para "bar". – Jeroen