R6 classes
The {R6}
package is an implementation of encapsulated object-oriented programming for R, and is a simpler, faster, lighter-weight alternative to R’s built-in reference classes. This style of programming is also sometimes referred to as classical object-oriented programming.
In this post I’ll be using the word class
to refer to the original class definition
using R6::R6Class()
and object
to refer to an instantiation of that class
e.g. my_object = ClassName$new()
.
It is possible to add a method to an existing R6 class after it has been defined, but I want to add a new method to an object (i.e. just an instance of this class).
R6 classes simple example
MyClass <- R6::R6Class(
"MyClass",
public = list(
hello = function(name) { cat("Hello", name, "\n")}
)
)
# Create an instance of the class
myobj <- MyClass$new()
# Call a method on this object
myobj$hello("#RStats")
## Hello #RStats
Modifying a Class
It is possible to create a class and then modify the definition of that class
afterwards. lock_class
must be set to FALSE to do this.
# Create an empty class
MyClass <- R6::R6Class(
"MyClass",
lock_class = FALSE
)
# Create a new method within the class after it was defined
MyClass$set("public", "hello", function(name) { cat("Hello", name, "\n")})
# Create an instance of the class
myobj <- MyClass$new()
# Call a method on this object
myobj$hello("#RStats")
## Hello #RStats
Adding a new method to an Object (withouth modifying the class)
It is possible to create a class, instantiate an object of that class, and then modify the contents of that object to add a new method not in the original class definition, but only to this object.
Requires:
lock_object = FALSE
- In order for a new method to behave correctly, is must have the same
environment as other methods in the class. This is so it can look-up public and
private variables in the class. e.g. using
self$
# Create an empty class
MyClass <- R6::R6Class(
"MyClass",
lock_object = FALSE,
public = list(
line_end = "!!",
hello = function(name) { cat("Hello", name, self$line_end, "\n")}
)
)
# Create an instance of the class
myobj <- MyClass$new()
# Call a method on this object
myobj$hello("#RStats")
## Hello #RStats !!
# Create a method Ensure it has the right environment
myobj$goodbye <- function(name) { cat("Goodbye", name, self$line_end, "\n")}
environment(myobj$goodbye) <- myobj$.__enclos_env__
myobj$goodbye("Mike")
## Goodbye Mike !!
What’s next?
This means I can establish a base class with a certain set of methods, but
I can now dynamically create a menagerie of slightly different objects which each have
different sets of methods.
I guess this is sort of similar to perhaps defining a class inheritance hierarchy except what I want to do is regularly, and dynamically, modify the methods available on existing objects during runtime.