La programación orientada a objetos de una forma u otra es muy posible en R. Sin embargo, a diferencia de, por ejemplo, Python, hay muchas formas de lograr la orientación a objetos:
- El paquete R.oo
- Clases S3 y S4
- Clases de referencia
- el paquete proto
Mi pregunta es:
¿Qué diferencias principales distinguen estas formas de programación OO en R?
Idealmente, las respuestas aquí servirán como referencia para los programadores de R que intentan decidir qué métodos de programación OO se adaptan mejor a sus necesidades.
Como tal, solicito detalles, presentados de manera objetiva, basados en la experiencia y respaldados por hechos y referencias. Puntos de bonificación por aclarar cómo estos métodos se corresponden con las prácticas estándar de OO.
Respuestas:
Clases S3
print
llamadasprint.lm
print.anova
, etc. Y si no se encuentra,print.default
Clases S4
Clases de referencia
proto
Clases R6
fuente
library("fortunes"); fortune("strait")
Editar el 8/3/12: la respuesta a continuación responde a una parte de la pregunta publicada originalmente que desde entonces se ha eliminado. Lo he copiado a continuación, para proporcionar contexto a mi respuesta:
Mi contribución se relaciona con su segunda pregunta, acerca de cómo los métodos OO de R se asignan a métodos OO más estándar. Mientras pensaba en esto en el pasado, volví una y otra vez a dos pasajes, uno de Friedrich Leisch y el otro de John Chambers. Ambos hacen un buen trabajo al articular por qué la programación tipo OO en R tiene un sabor diferente al de muchos otros lenguajes.
Primero, Friedrich Leisch, de "Creación de paquetes R: un tutorial" ( advertencia: PDF ):
El otro pasaje proviene del magnífico libro de John Chambers "Software para análisis de datos" . ( Enlace al pasaje citado ):
fuente
S3 y S4 parecen ser los enfoques oficiales (es decir, integrados) para la programación OO. Comencé a usar una combinación de S3 con funciones integradas en la función / método del constructor. Mi objetivo era tener una sintaxis de tipo object $ method () para tener campos semiprivados. Digo semiprivado porque no hay forma de ocultarlos realmente (hasta donde yo sé). Aquí hay un ejemplo simple que en realidad no hace nada:
#' Constructor EmailClass <- function(name, email) { nc = list( name = name, email = email, get = function(x) nc[[x]], set = function(x, value) nc[[x]] <<- value, props = list(), history = list(), getHistory = function() return(nc$history), getNumMessagesSent = function() return(length(nc$history)) ) #Add a few more methods nc$sendMail = function(to) { cat(paste("Sending mail to", to, 'from', nc$email)) h <- nc$history h[[(length(h)+1)]] <- list(to=to, timestamp=Sys.time()) assign('history', h, envir=nc) } nc$addProp = function(name, value) { p <- nc$props p[[name]] <- value assign('props', p, envir=nc) } nc <- list2env(nc) class(nc) <- "EmailClass" return(nc) } #' Define S3 generic method for the print function. print.EmailClass <- function(x) { if(class(x) != "EmailClass") stop(); cat(paste(x$get("name"), "'s email address is ", x$get("email"), sep='')) }
Y un código de prueba:
test <- EmailClass(name="Jason", "[email protected]") test$addProp('hello', 'world') test$props test class(test) str(test) test$get("name") test$get("email") test$set("name", "Heather") test$get("name") test test$sendMail("[email protected]") test$getHistory() test$sendMail("[email protected]") test$getNumMessagesSent() test2 <- EmailClass("Nobody", "[email protected]") test2 test2$props test2$getHistory() test2$sendMail('[email protected]')
Aquí hay un enlace a una publicación de blog que escribí sobre este enfoque: http://bryer.org/2012/object-oriented-programming-in-r Agradecería comentarios, críticas y sugerencias sobre este enfoque, ya que no estoy convencido. yo mismo si este es el mejor enfoque. Sin embargo, para el problema que estaba tratando de resolver, funcionó muy bien. Específicamente, para el paquete makeR ( http://jbryer.github.com/makeR ) no quería que los usuarios cambiaran los campos de datos directamente porque necesitaba asegurarme de que un archivo XML que representaba el estado de mi objeto se mantuviera sincronizado. Esto funcionó perfectamente siempre que los usuarios se adhieran a las reglas que describo en la documentación.
fuente