2011-01-18 14 views
8

Se un una classe denominata foo, allora è abbastanza semplice sovraccaricare la funzione summaryUtilizzando sd come funzione generica in R

summary.foo = function(x, ...) print("bar") 

Tuttavia questa tecnica non funziona con la funzione sd, cioè

> bar = createFooClass() 
> sd.foo = function(x, ...) print("Hi") 
> sd(bar) 
    error: is.atomic(x) is not TRUE 

Qual è il modo corretto di sovraccaricare questa funzione?

risposta

7

È possibile dirottare qualsiasi funzione non generico, renderlo (S3) generico e impostare la versione originale essere la versione predefinita. Ad esempio:

## make an S3 generic for sd 
sd <- function(x, ...) UseMethod("sd") 
## take the usual definition of sd, 
## and set it to be the default method 
sd.default <- stats::sd 
## create a method for our class "foo" 
sd.foo = function(x, ...) print("Hi") 

Una fase finale, se questo è in un pacchetto, è quello di aggiungere un argomento ... per sd.default per consentire passaggio di assegni pacchetto:

formals(sd.default) <- c(formals(sd.default), alist(... =)) 

dando:

> args(sd.default) 
function (x, na.rm = FALSE, ...) 
NULL 
> args(stats::sd) 
function (x, na.rm = FALSE) 
NULL 

Questo dà quindi il comportamento desiderato:

> bar <- 1:10 
> sd(bar) 
[1] 3.027650 
> class(bar) <- "foo" 
> sd(bar) 
[1] "Hi" 

Questo è documentato in section 7.1 delle estensioni di scrittura R manuali

+0

Meglio inviare una email a R-devel e richiedere che 'sd' (o meglio' var') sia reso generico. – hadley

+0

@hadley è d'accordo, ma oltre alla necessità per R Core di mantenerlo, c'è un impatto sulle prestazioni quando si crea qualcosa di generico, da qui la formulazione e il consiglio nella R Ext. Manuale. –

+0

Non compro quelle scuse. Perché dovrebbe significare generico e non var? – hadley

1

Guardare il codice di sd() --- invia in modo efficace internamente. In altre parole, non è una funzione generica, ma una normale funzione normale.

Il più semplice potrebbe essere quello di modificare sd() in ramo su classe foo.

+0

Stranamente questo è quello che ho fatto, ma mi sembrava "sbagliato" e un po 'imbarazzante. – csgillespie

3

È necessario definire un nuovo generico per sd.

Il modo più semplice è quello di utilizzare S4, perché gestisce il metodo predefinito "sd" automaticamente:

setClass("foo", list(a = "numeric", names = "character")) 

setGeneric("sd") 

setMethod("sd", "foo", 
      function(x, na.rm = FALSE){ 
       print("This is a foo object!") 
       callNextMethod([email protected]) 
       }) 

tf <- new("foo", a = 1:10) 
sd(tf) 
#[1] "This is a foo object!" 
#[1] 3.027650