Object oriented programming (OOP) is a programming language model that defines objects; which are elements in R that contain attributes, or fields, which have some specification in the definition of the object itself. Objects are defined in advance, and are very useful in conceptualising coding goals, and allowing the end-user a better experience when using your functions and/or code.
Base R has three different ways of defining objects, which are the three different models:
All of which have their merits and disadvantages. S3 is the simplest model, and is useful for defining a basic object. S4 is more complex, as classes have to be defined explicitly, but adds more clarity and allows inclusion of integrity checks. Reference Class is more complex again, but further improves on teh structure of the class definition, through incorporation of a higher degree of encapsulation.
For this example, I will be using the Reference Class model. This example is concerned with being able to deal a card from a standard card deck. To start with, we make a class called Card
which will contain two properties; the suit and the value. This is set up as follows.
Card <- setRefClass("Card",
fields = c(
suit = "character",
value = "numeric",
pairs = "numeric"
))
The setRefClass
function is used to create this class, and it has the two attributes that are required of a standard card. We can set up a function to deal a random card from a deck by now specifying two more commands.
dealHand = function(n){
y <- Card$new(n)
return(y)
}
Card$methods(
initialize = function(n){
suits <- c("Diamonds","Hearts","Clubs","Spades")
s <- sample(0:51, n)
.self$suit <- suits[(s %/% 13) + 1]
.self$value <- (s %% 13)+1
}
)
The function dealHand
has its only input as n
, which is the size of the hand. The assignment here is given by the initialize
method in the $methods
substructure of Card
. By setting the method of initialize
to randomly sample both value and suit, this will deal a random card every time that dealCard(n)
is run. For example:
dealHand(5)
## Reference class object of class "Card"
## Field "suit":
## [1] "Diamonds" "Spades" "Clubs" "Hearts" "Spades"
## Field "value":
## [1] 9 7 5 4 11
## Field "pairs":
## numeric(0)
We can also add another method that will recognise if there are any pairs in the hand that has been dealt. This is done by adding an additional method to Card$methods
, which takes the form
getPairs = function(){
pairval <- as.numeric(names(table(.self$value))[table(.self$value)>=2])
return(pairval)
}
So that now, if we are dealt a hand , we can see how many pairs there are in the hand, and what the value of the pair is:
set.seed(2)
hand = dealHand(5)
hand$getPairs()
hand
## Reference class object of class "Card"
## Field "suit":
## [1] "Hearts" "Hearts" "Diamonds" "Spades" "Clubs"
## Field "value":
## [1] 8 2 6 11 6
## Field "pairs":
## [1] 6
Functional programmings is (obviously) focused on using functions. We call functions ‘first class’, because they
You can consider functions as another type of variable, as you would store and use them in similar ways. For example, consider the list of functions
mylist = list(add_function = function(x,y) x+y, subtract_function = function(x,y) x-y)
mylist$add_function(1,2)
## [1] 3
mylist$subtract_function(2,1)
## [1] 1
You can see how this could be useful, in setting a list of different functions. Applications could include including a list of link functions in some form of regression, or basis functions. Functions can also return other functions, consider
make_link_function = function(which_f){
if(which_f == "exponential") f = function(x) exp(x)
if(which_f == "identity") f = function(x) x
return(f)
}
link_function = make_link_function("exponential")
link_function(1:5)
## [1] 2.718282 7.389056 20.085537 54.598150 148.413159
This is a style of function output that could be used in making a general linear model, for example, to link the parameter to the predictor.
In regards to functional programming, there are some important definitions:
function(exp) function(x) x^exp
returns a function that will raise x
to the power of exp
. If you change the value of exp
after defining the first function, it will change what power x
is raised to later on, even though the function was defined before exp
was changed.