
El sistema de clases de los objetos en R proporciona alguno de los mecanismos de la programación
orientada a objetos como el despacho del método (
method dispatch) y la herencia.
El método es la implementación de un algoritmo que representa una operación o función que un objeto realiza. El conjunto de los métodos de un objeto determinan el comportamiento del objeto. En R, el despacho del método consiste en examinar la clase de los argumentos de una función para decidir (despachar) la versión adecuada para los objetos de esa clase. No todas las funciones de R tienen despacho del método. Las que sí lo tienen se llaman funciones genéricas.
La herencia permite a los programadores crear nuevas clases, similares a otras ya existentes. Únicamente deberán proporcionar métodos adecuados para las nuevas clases o mantener los heredados. Un objeto de R que hereda las propiedades de un objeto ya definido, tiene como atributo de clase un vector que contiene la clase de ese objeto (en primer lugar), junto con las clases del objeto del que hereda.
El primer mecanismo de la programación orientada a objetos en R es el conjunto de clases
S3 o del
viejo estilo (
old-style), donde el despacho del método se produce a través de las funciones genéricas del siguiente modo:
Supongamos que tenemos un objeto con el nombre de
cdr
de la clase
Cuadrado
, el cual es una subclase de
Rectangulo
que a su vez es una subclase de
Forma
. El mecanismo de despacho del método consiste en S3 y la función
UseMethod
. Utilizando S3 definimos un método
Area
para la clase
Rectangulo
como
Area.Rectangulo <- function(objeto) { attr(objeto, "ladoA") * attr(objeto, "ladoB"); }
dado que un objeto
Rectangulo
tiene dos atributos
ladoA
y
ladoB
(ahora se puede acceder directamente a los argumentos con el operador
@
, es decir,
objeto@ladoA
y
objeto@ladoB
, respectivamente). Entonces definimos la
función genérica Area
así:
Area <- function(objeto, ...) UseMethod("Area");
Cuando esta función se aplica en el objeto con
Area(cdr)
,
UseMethod
despachará el método basado en la clase del primer argumento, es decir,
objeto
. Como
cdr
es de la clase
Cuadrado
, primero buscará un método llamado
Area.Cuadrado
. Si no existe, como en este caso, probará con
Area.Rectangulo
y así sucesivamente. Si no existiera ningún método específico para cualquiera de las clases del
objeto
, entonces se recurrirá al método
Area.default
que siempre debemos tener.
Observemos que las funciones genéricas S3 se pueden reconocer por la utilización de
UseMethod
en su código. Esto es importante, ya que las páginas de ayuda para una combinación de método y objeto depende de su nombre completo del tipo
"function.class"
. Por ejemplo, la página de ayuda de la función
summary
no explica absolutamente nada sobre su actuación cuando le pasamos un objeto de la clase
factor
. Será mejor buscar la ayuda de la función
summary.factor
, aunque para que la función actúe sólo hay que escribir
summary(objeto)
.
Cuando se crea una clase, asociadas a ella, deberemos crear un conjunto de funciones para extraer datos o información sobre los objetos de esa clase. Dada la convención explicada sobre los nombres de las funciones en las clases S3, podemos utilizar la función
apropos
para hallar los métodos disponibles para una clase:
> apropos('.*\\.factor$')
[1] "all.equal.factor" "as.character.factor" "as.data.frame.factor"
[4] "as.Date.factor" "as.factor" "as.list.factor"
[7] "as.POSIXlt.factor" "as.vector.factor" "codes.factor"
[10] "[<-.factor" "[.factor" "[[.factor"
[13] "format.factor" "is.factor" "is.na<-.factor"
[16] "length<-.factor" "levels<-.factor" "Math.factor"
[19] "Ops.factor" "print.factor" "rep.factor"
[22] "summary.factor" "Summary.factor" "xtfrm.factor"
Así descubriremos que existen algunas funciones específicas para la clase
factor
.
Ahora bien, como el despachado del método que proporcionan las clases S3 está limitado al primer argumento de la función, y como las convenciones sobre los nombres que hemos explicado pueden crear alguna confusión, se decidió crear un nuevo sistema de clases S4 o de nuevo estilo (
new-style). Éste es ahora el sistema preferido en el desarrollo de R.
En las clases S4, las funciones genéricas se reconocen por la llamada a una función
standardGeneric
en su definición.
Las funciones necesarias para trabajar con las clases S4 se hallan en el paquete
methods
. Por ejemplo, para saber si un objeto utiliza el nuevo estilo podemos hacer:
> temp <- c(20,15,15,20,20,30,25,25,30,15,25,30,30)
> temp <- factor(temp)
> isS4(temp)
[1] FALSE
Para saber los métodos asociados a una clase S4 como los objetos
mle
, resultado de la función de estimación de máxima verosimilitud, hacemos:
> library(methods)
> showMethods(class='mle')
Descubriremos que se puede calcular la matriz de varianzas-covarianzas de un objeto
mle
con la función
vcov
.
Aunque no hay una función genérica
print
para las clases S4, la función
show
permite ver el contenido de un objeto.
Por otra parte, los elementos que componen un objeto S4 se guardan en los llamados
slots. Para ver los tipos de
slots en un objeto, podemos utilizar la función
showClass
.
> library(stats4)
> showClass("mle")
Class “mle” [package "stats4"]
Slots:
Name: call coef fullcoef vcov min details minuslogl
Class: language numeric numeric matrix numeric list function
Name: method
Class: character
Para acceder directamente a un slot de un objeto, utilizaremos el operador
@
del mismo modo que el operador
$
para una lista. La función
slot
también obtiene el mismo resultado.
> slot(objeto.lme,"vcov")