Learn R Programming

oops (version 0.2.0)

oClass: Create an Object Class

Description

Create a function used to generate instances (environments) with the specified class and fields.

Usage

oClass(
  name = NULL,
  inherit = NULL,
  portable = FALSE,
  hash = FALSE,
  formals = NULL,
  ...
)

Arguments

name

character string describing the name of the class

inherit

oClass used as the parent.env for the generated instances

portable

logical indicating whether all inherited values should be copied into each instance

hash

logical indicating whether instances should use hashing, see new.env

formals

list containing the formal arguments for the resulting generator function. These are passed to the init function when a new instance is created.

...

named fields inherited by the class instance

Value

a function of class "ClassGenerator" with attributes describing each generated class instance

Details

oClass is used to create classes with reference semantics that modify in place similar to R5 and R6 classes. Unlike those, functions on oClass instances dispatch using the standard S3 dispatch system. Furthermore, oClass objects and instances are created similar to other R objects to ensure that they are easy and painless to use.

To create a new object class, provide its name and a named list of its fields and their default values. This generates a function that creates a new "instance" of the class each time that it is called. For example, poly <- oClass("polygon", sides = NA) creates a new class called "polygon" with a field called "sides" that can be created using poly(). Object methods that act on the instance are created in the same manner as S3 methods. Therefore, class methods should be created separately.

Each instance of the object class is an environment. The parent environment of the instance is attached to the attributes of the function created by the oClass function. This environment in the function attributes serves as a instance template. Any variables that are specified during the creation of the object instance are placed within the environment of said instance. When searching for an object within an instance, the instance environment is first searched, then the template. This ensures that each object instance remains as small as necessary and minimizes copying. A hashmap is not used by default so that the instance size is smaller, but this can be changed by the oClass function.

oClass objects can also inherit other class objects. If another class object is inherited, the template environment in the inherited object's attributes is added to each instances search path. Furthermore, the name of the inherited class **(and all classes it inherits)** is added to each instance's S3 class. If an environment is inherited, then it is added to the search path.

Since oClass relies on pointers to other environments, oClass instances are generally not portable. If portable=TRUE is added, then each instance will include the default values of each inherited oClass. This generally increases creation time and memory usage, but may result in marginally faster field access. If the fields are relatively few and small, though, memory usage may decline when each Instance is portable.

oClass instances automatically call init when created. Write custom S3 methods for init to control this behavior. This requires the Class to be named so that instances inherit the named S3 class. The formals defines the Class generator's formal function arguments. If used, then an init method for the Class should be created with identical formal arguments; otherwise, instance creation may fail. If no formals are defined, then all objects passed to the generator function are passed to init at creation.

Examples

Run this code
# NOT RUN {
## Creating a Stack
stack <- oClass(
  "stack",
  data = list()
)

# Methods
print.stack <- function(x, ...) print(x$data, ...)
push <- function(x, item){
  x$data[[length(x$data)+1]] <- item
  x
}
pop <- function(x){
  n <- length(x$data)
  last <- x$data[[n]]
  x$data[[n]] <- NULL
  last
}

# Create a new instance
x <- stack()
push(x, 6)
push(x, 7)

identical(x$data, list(6, 7)) # TRUE

last <- pop(x)
identical(last, 7)            # TRUE
identical(x$data, list(6))    # TRUE


## Person/Student
##   Example of Inheritance and using Formals

# Declare formal arguments of Person Generator
Person <- oClass(
  "Person",
  formals = list(first, last)
)

# Formal arguments of init should match Person
init.Person <- function(x, first, last){
  x$first <- first
  x$last  <- last
  return(x)
}

# Create init for Student class
init.Student <- function(x, first, last, year = 1, major = "Econ", ...){
  x$year  <- year
  x$major <- major
  add_fields(x, ...)
  init_next(x, first = first, last = last)
  return(x)
}

# Create Student class, inherits Person
Student <- oClass(
  "Student",
  inherit = Person,
  formals = init.Student
)

# Creating a student
Student("Chris", "Mann", 4, gpa = 4.0)

# }

Run the code above in your browser using DataLab