2014-12-23 5 views
8
f <- function() 1 
g <- function() 2 
class(g) <- "function" 
class(f) ## "function" 
class(g) ## "function" 
length.function <- function(x) "function" 
length(f) ## 1 
length(g) ## "function" 
+3

Benvenuti in SO! Per favore leggi [la pagina di aiuto] (http://stackoverflow.com/help/on-topic) per capire meglio come esprimere la tua domanda. Inoltre, si prega di utilizzare i tag del codice quando si condivide il codice. Puoi aggiungerli tramite l'editor. – Chrismas007

+2

@Carlise: non fa per me (come dimostrato nella mia modifica). Penso che questo sia un interessante rompicapo sui meccanismi interni di R. –

+0

Questo è interessante. Nota che 'attr (g," class ")' fornisce "function" ma 'attr (f," class ")' fornisce NULL. – Dason

risposta

5

Innanzitutto, length non è una tipica funzione generica, ma piuttosto un "Internal Generic Function". Si può vedere questo guardando la sua definizione:

> length 
function (x) .Primitive("length") 

Confronta questo per una tipica funzione generica:

> print 
function (x, ...) 
UseMethod("print") 
<bytecode: 0x116ca6f90> 
<environment: namespace:base> 

length chiamate direttamente in .Primitive che poi può fare la spedizione, se non gestisce la chiamata in sé ; l'approccio tipico è chiamare direttamente UseMethod che gestisce solo la spedizione. Si noti inoltre che non v'è alcuna funzione length.default perché il codice nella chiamata .Primitive lo fa:

> methods("length") 
[1] length.function length.pdf_doc* length.POSIXlt 

non sono sicuro che sia completamente definito quando un generico interno esaminerà metodi definiti dall'utente e quando sarà utilizzare solo interno quelli; Penso che l'idea generale sia che per una classe definita dall'utente (pacchetto, non core), verranno utilizzati i metodi forniti. Ma l'override per le classi interne può o non può funzionare.

Inoltre (sebbene non strettamente pertinente per questo caso), anche per un tipico metodo generico, la documentazione è ambigua riguardo a cosa dovrebbe accadere quando la classe viene derivata implicitamente piuttosto che come attributo. Innanzitutto, quali rapporti class() rappresentano una fusione di cose. Dalla pagina class aiuto:

Molti oggetti R hanno un attributo class, un vettore personaggio che dà i nomi delle classi da cui l'oggetto eredita. Se l'oggetto non ha un attributo di classe, ha una classe implicita, "matrix", "array" o il risultato di mode(x) (eccetto che i vettori integer hanno classe implicita "integer").

Così, nonostante class restituire la stessa cosa per f e g, non sono la stessa cosa.

> attributes(f) 
$srcref 
function() 1 

> attributes(g) 
$srcref 
function() 2 

$class 
[1] "function" 

Ora, qui è dove diventa ambiguo. L'invio del metodo è descritto in (almeno) 2 punti: la pagina di aiuto class e la pagina di aiuto UseMethod. UseMethod dice:

Quando viene applicata una funzione di chiamata UseMethod("fun") ad un oggetto con attributo class c("first", "second"), il sistema cerca una funzione chiamata fun.first e, se lo trova, lo applica all'oggetto. Se non viene trovata alcuna funzione di questo tipo, viene provata una funzione chiamata fun.second. Se nessun nome di classe produce una funzione adatta, viene utilizzata la funzione fun.default, se esiste, o si verifica un errore.

Mentre class dice:

Quando una divertente funzione generica viene applicata a un oggetto con attributo class c("first", "second"), il sistema cerca una funzione chiamata fun.first e, se lo trova, lo applica alla oggetto.Se non viene trovata alcuna funzione di questo tipo, viene provata una funzione chiamata fun.second. Se nessun nome di classe produce una funzione adatta, viene utilizzata la funzione fun.default (se esiste). Se non esiste un attributo di classe, viene provata la classe implicita, quindi il metodo predefinito.

La vera differenza è l'ultima frase che la pagina class ha quel UseMethod non lo fa. UseMethod non dice cosa succede se non esiste un attributo class; class dice che la classe implicita è usata per la spedizione. Il tuo codice sembra indicare che ciò che è documentato in class non è corretto, poiché length.function sarebbe stato chiamato per g.

Cosa succede nella distribuzione del metodo quando non c'è alcun attributo di classe probabilmente richiederà di esaminare il codice sorgente in quanto la documentazione non sembra essere di aiuto.

Problemi correlati