2012-08-24 14 views
7

Correlato alla domanda this, ma leggermente diverso e, si spera, più chiaro.Invio di stile S3 per oggetti S3 utilizzando le definizioni di metodo formale

Sto cercando un pulito modo per registrare formalmente i metodi per entrambe le classi S4 e S3, ma senza fare affidamento sul terribile schema di denominazione dei punti S3 per la spedizione. Un esempio:

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); 

Questo esempio mostra come si possa registrare un metodo test per gli oggetti della classe S3 bar, senza la necessità di nominare la funzione test.bar, che è grande. Tuttavia, la limitazione è che se registriamo i metodi in questo modo, verranno inviati solo alla prima classe S3 dell'oggetto. Per esempio:

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

Questo non funziona, perché il metodo S4 invio cercherà solo di classe foo e le sue superclassi. Come è possibile estendere questo esempio in modo che selezioni automaticamente il metodo test per bar quando non è stato trovato alcun metodo appropriato per foo? Per esempio. Dispacciamento di stile S3 ma senza dover tornare a nominare tutto test.foo e test.bar?

Quindi, in breve: come creare una funzione generica che utilizza il dispacciamento del metodo formale, ma in aggiunta ricade sulla seconda, terza, classe di un oggetto per oggetti S3 con più classi.

risposta

2

si potrebbe scrivere un metodo

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) 

Ma io personalmente non mescolare S3 e S4 in questo modo.

+0

Sì, ho fatto qualcosa di simile; tuttavia il fatto che in realtà stai cambiando l'attributo di classe di x lungo la strada può avere effetti collaterali indesiderati ... Esiste un modo per inviarlo al metodo successivo senza modificare l'oggetto stesso? – Jeroen

+0

Non ho una risposta per te; Penso che il metodo S4 per 'bar' che lavora su una 'barra' di classe S3 sia un incidente di implementazione e tu stai costruendo una struttura complessa su basi molto traballanti. –

3

?setOldClass darà la risposta:

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

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

Quindi questo è esattamente * non * quello che voglio. Richiede un'ereditarietà formale tra le classi "foo" e "bar", che potrebbe non essere il caso. Voglio che funzioni per qualsiasi oggetto arbitrario con class = [x, "bar"] per x = qualsiasi cosa, senza dover dichiarare l'ereditarietà tra x e "bar" per ogni possibile classe x. Supponiamo che qualcun altro abbia creato un oggetto con classi ["zoo", "bar"], quindi la funzione 'test()' dovrebbe essere abbastanza intelligente da selezionare il metodo per "barra". – Jeroen