Object Oriented Programming in R

January 20, 2012
By

(This article was first published on Jason Bryer » R, and kindly contributed to R-bloggers)

As someone who was a Java programmer for many years learning R’s object oriented programming framework has been frustrating to say the least. I like the simplicity of S3 but find it limiting when you wish to write methods that change the underlying data elements. That is, printing, summarizing, and plotting work great because they generally do not require changes to the data in the class passed to it. After much experimenting it occurred to me that perhaps I could achieve a more Java like behavior by adding functions to the class. For simple things this works great. To make it even more flexible I found that if you change the list to an environment before assigning the class allows one to change lists within the list.

The following example models the framework for an email class (without actually doing anything useful). That is, I want a class that contains an email address and name and the ability to send email. I would also like to save a history of the emails sent. As can be seen, functions that work with atomic variables are pretty straight forward. Working with lists require (well maybe required, if you know of a better way leave a comment) using the assign function. This may not produce the cleanest source code but (IMHO) provides a better experience for the user.

#' 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 functions
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=''))
}

if(FALSE) { #Test code that won't be run when sourcing this file
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]')
}

view raw EmailClass.R This Gist brought to you by GitHub.

To leave a comment for the author, please follow the link and comment on his blog: Jason Bryer » R.

R-bloggers.com offers daily e-mail updates about R news and tutorials on topics such as: visualization (ggplot2, Boxplots, maps, animation), programming (RStudio, Sweave, LaTeX, SQL, Eclipse, git, hadoop, Web Scraping) statistics (regression, PCA, time series, trading) and more...



If you got this far, why not subscribe for updates from the site? Choose your flavor: e-mail, twitter, RSS, or facebook...

Tags:

Comments are closed.