The R Project SVN R

Rev

Rev 52856 | Blame | Compare with Previous | Last modification | View Log | Download | RSS feed

\name{ReferenceClasses}
\alias{ReferenceClasses}
\alias{setRefClass}
\alias{refClassFields}
\alias{refClassMethods}
\alias{refClassRepresentation-class}
\alias{refClass-class}
\alias{refObject-class}
\alias{classMethodDef-class}
\alias{SuperClassMethod-class}
\alias{show,classMethodDef-method}
\alias{show,refClassRepresentation-method}
\title{
Creating Classes With Fields Treated by Reference (OOP-style)
}
\description{
A call to \code{setRefClass} defines an \R class with
fields that
are accessed by reference and with class-based methods to be invoked on objects
from the class, in the style of languages such as Java and
C++, commonly referred to as OOP languages.
The application interface provided is designed to deal consistently
with such classes whether implemented entirely in \R{} or through an
interface to another language.
}
\section{NOTE:}{
The software described here is an initial version.  The eventual goal
is to support reference-style classes with software in \R itself
or using inter-system interfaces.  The current implementation (\R
version 2.12.0) is preliminary and subject to change, and currently
includes only the \R-only implementation.  Developers are encouraged
to experiment with the software, but the description here is more than
usually subject to change.

A comment on terminology.  Some terms are needed to distinguish the
OOP-style structure from the similar function-based classes and methods
structure.  For the moment, the terms \dQuote{field} and
\dQuote{class-based method} are used in distinction to \dQuote{slot}
and \dQuote{method} for the usual S4 things.
Other suggestions are welcome, but there are  arguments for and
against most obvious terminology borrowed from other languages.  And,
as mentioned below, even the term \dQuote{OOP} is potentially confusing.
}
\usage{
setRefClass(Class, fieldClasses = , contains = , classMethods =,
   fieldPrototypes =, basicRefClass = "stdRefClass",
   refClassName = Class, where =, ...)

refClassFields(Class)
refClassMethods(Class)
}
\arguments{
  \item{Class}{
character string name for the class.
}
  \item{fieldClasses}{
a named list of the fields, to be handled by reference semantics (see
the corresponding section below).  Note that these are distinct from
the slots, if any, in the object.  Slots are, as always, handled by
standard \R{} object management.
}
  \item{contains}{
optional vector of superclasses for this class.  If a superclass is
also a reference class, the fields and class-based methods will be inherited.
}
  \item{classMethods}{
a named list of function definitions that can be invoked on objects
from this class.  See the section on class-based methods below, and in
particular the comments on accessor methods for fields.
}
  \item{fieldPrototypes}{
an optional named list of prototype objects for a subset of the
fields.  By default, each field will be initialized to the prototype
object of the corresponding class.
}
  \item{basicRefClass}{
the name of a reference class from which the new class expects to inherit methods
to manage the reference semantics.
The design goal is to define distinct implementations of reference
through a set of basic reference classes.
The default, \code{"stdRefClass"}, implements reference objects
entirely in \R{} (currently by using environments); other choices of
basic reference class might use an interface to another language.  See
the section on inter-system interfaces.
}
  \item{refClassName}{
optionally, a name for the class to be used in interfacing to another
language, if for some reason that name is not suitable as an \R{}
class name.  By default, and usually, the name provided by
argument \code{Class} is used.
}
  \item{where}{
the environment in which to store the class definition.  Defaults to
the package namespace or environment for code that is part of an \R{}
package, and to the global environment for code sourced directly at
the session top level.
}
  \item{\dots}{
other arguments to be passed to \code{\link{setClass}}.
}
}

\section{Reference Objects}{
Normal objects in \R are passed as arguments consistently with
functional programming semantics; that is, changes made to an object
passed as an argument are local to the function call.  The object that
supplied the argument is unchanged.

Functional object semantics (sometimes called pass-by-value) are
suitable for many statistical computations and are implicit, for
example, in the basic \R software for fitting statistical models.
In other situations, one would like all the code dealing with an
object to see the exact same content, so that changes made in any
function call would be reflected everywhere.
This is often suitable if the object has some \dQuote{objective}
reality, such as a window in a user interface.

In addition, a number of languages, such as Java and C++ and many
others, support a version of classes and methods assuming reference
semantics.
The basic programming mechanism is to invoke a method on an object,
different in several respects from a function call in \R.
In the \R syntax we use for this operation, one invokes a method,
\code{m1} say, on an object \code{x} by the expression
\code{x$m1(...)}.  It's not a logical necessity that such %$
class/method systems use reference semantics, essentially all of them
do.
In particular, they usually include methods that modify the content of
the object.

The goal of the software described here is to provide a uniform
programming style in \R to deal with such software, whether it is
implemented directly in \R or through an interface to one of the other
languages.
Several implications follow for the \R software.
Methods in this model are associated with the object, or more
precisely with the class of the object, as opposed to methods in a
function-based class/method system, which are fundamentally associated
with the function (in \R, for example, a generic function in an \R
session has a table of all its currently known methods).

This relation of methods to objects is one reason such systems are
often referred to as Object Oriented Programming (OOP).  While there
is nothing incorrect about the term, it has been the cause of
confusion, particularly when programmers come to \R from one of the
other systems.
In a normal use of the words, the function-based class/method system in \R
is just as object-oriented as Java, say, if not more so.
But the systems are fundamentally different.
To avoid propagating the confusion, we will avoid the term OOP
throughout this document.
If we need to make the distinction, we will refer to class-based
methods versus function-based methods.
}
\section{Fields and Class-Based Methods}{
All the widely used languages implementing class-based methods provide
for named \dQuote{pieces} of an object.
The term for these pieces varies with the language; in the \R
implementations they will be called \emph{fields}.
In many languages, a field is accessed by using the operator
\code{"."}, but this is not available to us in \R because the
character can be part of a name (blame it on the Unix system whose
convention of starting hidden files with \code{"."} was taken over in
S).

Instead, and rather than introduce yet another operator into the
grammar, we use the \code{$} operator, %$
as has been done in a number of related \R packages, including
inter-system interfaces to languages such as Java and C++.
A field is extracted by this operator and modified by the operator
appearing on the left of an assignment.
In terms of implementation, any class representing reference objects
of this form will have or inherit methods for \code{"$"} and
\code{"$<-"}.
Objects from reference classes will inherit
these methods from a basic reference class, either using \R (the
standard being class \linkS4class{stdRefClass}) or interfacing to
another system.

Similarly, a class-based method is invoked on an object using the \code{$}
operator.  To invoke a class-based method \code{undo} on an object \code{x},
call \code{x$undo()}.
}

\section{Writing Class-Based Methods}{
Class-based methods are functions supplied as elements of a named list as
the argument \code{classMethods} in a call to \code{setRefClass}.
They are written as ordinary \R functions but have some special
features and restrictions.
The body of the function can contain calls to any other class-based method,
including those inherited from other reference classes.

Class-based methods also need to refer to fields in the object.
A number of
class-based systems recommend or enforce \emph{accessor methods}
corresponding to each field.
In the \R version presented here (and fairly often elsewhere
as well), a field named \code{abc} of an object \code{x} would be
extracted by \code{x$getAbc()} and assigned by
\code{x$setAbc(value)}.
Aside from other reasons, using accessor methods in the standard \R
implementation allows class-based methods to be defined independently of the
precise mechanism currently used to implement fields (see the
implementation section below).
A requirement for defining reference classes in \R is that methods be
available to get any field and to set any field, although an error
may be generated if a field is defined to be read-only.

For reference classes using the \linkS4class{stdRefClass} basic
reference class, the use of accessor methods is optional.
An alternative is to use the field name directly for getting the field
and assignments of the field name using the
non-local assignment operator, \code{<<-}, to set the field.  See the
second version of class-based methods in the example below.
Notice that non-local assignment is required:  a local assignment with
the \code{<-} operator just creates a local object in the function
call, as it would in any \R function.

Direct access to fields in a class-based method usually gives a simpler and slightly faster
implementation.
However, using accessor methods is required if the reference
object is a proxy for an object in another language.
Using them in the \R-only case as well has the advantage of being compatible
with the external case, so the same method definition applies to both.
That's an important advantage in principle, because
one of the main goals for the software described here is to provide a
consistent programming interface both for \R-only software and for
inter-system interfaces.

class-based methods should be kept simple; if they need to do some
specialized \R computation, put that into a separate, ordinary
function and write the method to call that.
Specifically, methods can not use special features of the
enclosing environment mechanism.
methods can not themselves be generic functions; if you want
additional function-based method dispatch, write a separate generic
function and call that from the method.
The implementation section explains the reason for these restrictions.

The entire object can be referred to in a method by the reserved
name \code{.self}, as shown in the \code{save=} method of the
example.

The methods defined in the class include methods from superclasses, as
discussed in the next section.
}
\section{Inheritance}{
Reference classes inherit from other reference classes by using the
standard \R inheritance; that is, by including the superclasses in the
\code{contains=} argument when creating the new class.
Non-reference classes can also be included in the \code{contains=} argument.  The class definition
mechanism treats reference and non-reference superclasses slightly differently.
If the contained reference classes themselves have reference
superclasses, these will be moved ahead of any non-reference
superclasses in the class definition (otherwise the ordering of
superclasses may be ambiguous).
The names of the reference superclasses are in slot
\code{refSuperClasses} of the class definition.

Class fields are inherited.  Currently the new class definition can
override any inherited fields:  the previous field definition is no
longer available.

Inherited methods are installed in the same way as directly
specified methods.
The code in a method can refer to  inherited methods in the same
way as directly specified methods.

A method may override a method of the same name in a superclass.  For
this purpose, a special method name will be provided, to be translated
into a call to the superclass method overridden.  This mechanism has
not yet been implemented, but the current plan is that
\code{callSuper(...)} will translate into a call to the superclass
version of the current method.
See the matrix viewer example below.

}
\section{Implementation}{
Reference class definitions need to store the definition of the fields
and also the class-based methods (since these belong to the class in the
class-based paradigm).
These and some other properties are defined in the class
\code{refClassRepresentation}, which is a subclass of the ordinary
class definition class, \linkS4class{classRepresentation}.
As of version 2.12.0 of \R, the details of this class are not part of
the API.
Helper functions \code{refClassFields} and \code{refClassMethods} will
extract class field and method information.
It's a bad idea to count on the specific slots as currently documented
(to satisfy package checking).

The implementation provides for field and class method access through
the \code{$} operator. %$
This includes replacement of field values in a reference class object.
Class method definitions are also supported as documented here.

The implementation for both purposes works by delivering a function
object for the method with an environment containing the fields and
class-based methods as objects, specifically
the environment of the object itself.
The \code{initialize} method for standard reference class objects
installs an environment in the object with the initial contents of the
class fields (either the defaults from the prototype or values
supplied explicitly in the call to \code{\link{new}}).
Methods are inserted into the environment when they are called,
including other methods they may call.
These dependencies are searched heuristically when the reference class
is defined, using the \code{findGlobals} function in recommended
package \code{codeTools}.
This recommended package must be available to define a reference class
(but is not required to use reference classes defined in an installed package).
}
\section{Inter-System Interfaces}{
A number of \R packages currently support interfaces to other
languages using a similar reference-based programming model.
Aside from differences in choice of terminology and other details,
many of these are largely compatible with the programming style
described here.

The inter-system interface approach could also be added to the
reference class approach here, for example by having a basic reference
class that was a subclass of \code{stdRefClass} but assembled methods
and field accessors that were proxies to the facilities in the other
language.  Such an implementation would allow users to write \R
software that extended methods and fields in the other language with
additional ones implemented in \R.  Users of such packages should see
a consistent interface to both sets of fields and methods.  As of
version 2.12.0 of \R, this remains a topic for future development.
}
\value{
\code{setRefClass} returns the class definition, invisibly, but the function is mainly
called for the side effect of assigning the definition, usually as
part of an \R{} package.

\code{refClassFields} returns a list of the classes for all the class
fields.

\code{refClassMethods} returns a list of the class method functions,
including those inherited and accessor methods generated.

}
\author{
John Chambers
}


 \examples{
## a simple editor for matrix objects.  Method  edit() changes some
## range of values; method undo() undoes the last edit.
setRefClass("matrixEditor",
      fieldClasses = list( data = "matrix",
        edits = "list"),
      classMethods = list(
        edit = function(i, j, value) {
          x <- getData()
          backup <-
            list(i, j, x[i,j])
          setEdits(c(list(backup),
            getEdits()))
          x[i,j] <- value
          setData(x)
          invisible(value)
        },
        undo = function() {
          prev <- getEdits()
          if(length(prev)) prev <- prev[[1]]
          else stop("No more edits to undo")
          edit(prev[[1]], prev[[2]], prev[[3]])
          ## trim the edits list
          setEdits(
            getEdits()[-(1:2)])
          invisible(prev)
        },
        save = function(file) {
          base::save(.self, file = file)
        }
      )
    )
xMat <- matrix(1:12,4,3)
xx <- new("matrixEditor", data = xMat)
xx$edit(2, 2, 0)
xx$data
xx$undo()
stopifnot(all.equal(xx$data, xMat))
\dontshow{
tf <- tempfile()
xx$save(tf) #$
load(tf)
unlink(tf)
stopifnot(identical(xx$data, .self$data))
}
## A version of the classMethods= argument above that
## is a little simpler and faster but only works with
## the implementation in R, not with interfaces:
localMethods <- list(
     edit = function(i, j, value) {
         backup <-
             list(i, j, data[i,j])
         edits <<- c(list(backup),
                     edits)
         data[i,j] <<- value
         invisible(value)
     },
     undo = function() {
         prev <- getEdits()
         if(length(prev)) prev <- prev[[1]]
         else stop("No more edits to undo")
         edit(prev[[1]], prev[[2]], prev[[3]])
         ## trim the edits list
         length(edits) <<- length(edits) - 2
         invisible(prev)
     },
     save = function(file) {
         base::save(.self, file = file)
     }
)
setRefClass("matrixEditor2",
      fieldClasses = list( data = "matrix",
        edits = "list"),
      classMethods = localMethods)

## Inheriting a reference class:  a matrix viewer
setRefClass("matrixViewer", contains = "matrixEditor",
    classMethods = list( view = function() matplot(data),
        edit = # invoke previous method, then replot
          function(i, j, value) {
            callSuper(i, j, value) # but this doesn't yet work
            view()
          }))

\dontshow{
ff = new("matrixEditor2", data = xMat)
## uncomment when callSuper() works
## ff$edit(2,2,0)
## ff$data
## ff$undo()
## stopifnot(all.equal(ff$data, xMat))
removeClass("matrixEditor")
removeClass("matrixEditor2")
removeClass("matrixViewer")
}
}
\keyword{ programming }
\keyword{ classes }