`$`
operator in R.
The field and method computations potentially modify the object.
All computations referring to the objects see the modifications, in contrast to
the usual functional programming model in R. A call to
setRefClass
in the source code for a package defines the class and returns a generator object.
Subsequent calls to the $methods()
method of the generator will define methods for the class.
As with functional classes, if the class is exported from the package,
it will be available when the package is loaded. Methods are R functions. In their usual implementation, they refer to fields
and other methods of the class directly by name. See the section on
“Writing Reference Methods”. As with functional classes, reference classes can inherit from other
reference classes via a contains=
argument to
setRefClass
. Fields and methods will be inherited, except where the
new class overrides method definitions. See the section on “Inheritance”.setRefClass(Class, fields = , contains = , methods =,
where =, inheritPackage =, ...)getRefClass(Class, where =)
In the call to getRefClass()
this argument can also be any
object from the relevant class.
Note that fields are distinct from slots. Reference classes should not define class-specific slots. See the note on slots in the “Implementation” section.
$methods
method on the generator object returned.
See the section on “Writing Reference Methods” for details.
setRefClass
, the environment in which to store the class definition. Should be
omitted in calls from a package's source code.For getRefClass
, the environment from which to search for the definition. If the
package is not loaded or you need to be specific, use
asNamespace
with the package name.
FALSE
. See the Section “Inter-Package Superclasses
and External Methods”.
setClass
.
In the call to getRefClass()
this argument can also be any
object from the relevant class.
Note that fields are distinct from slots. Reference classes should not define class-specific slots. See the note on slots in the “Implementation” section.
$methods
method on the generator object returned.
See the section on “Writing Reference Methods” for details.
setRefClass
, the environment in which to store the class definition. Should be
omitted in calls from a package's source code.For getRefClass
, the environment from which to search for the definition. If the
package is not loaded or you need to be specific, use
asNamespace
with the package name.
FALSE
. See the Section “Inter-Package Superclasses
and External Methods”.
setClass
.
setRefClass()
returns a generator function suitable for
creating objects from the class, invisibly. A call to this function
takes any number of arguments,
which will be passed on to the initialize method. If no
initialize
method is defined for the class or one of its
superclasses, the default method expects named arguments with the
name of one of the fields and unnamed arguments, if any, that are
objects from one of the superclasses of this class (but only
superclasses that are themselves reference classes have any effect). The generator function is similar to the S4 generator function
returned by setClass
. In addition to being a generator
function, however, it is also a reference class generator object,
with reference class methods for various utilities. See the section
on reference class generator objects below. getRefClass()
also returns the generator function for the
class. Note that the package slot in the value is the correct package
from the class definition, regardless of the where
argument,
which is used only to
find the class if necessary."$"
for this operation; one invokes a method,
m1
say, on an object x
by the expression
x$m1(...)
. Methods in this paradigm 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).
In this document “methods for a class” as opposed to
“methods for a function” will make the distinction. Objects in this paradigm usually have named fields on which
the methods operate.
In the R implementation, the fields are defined when the class is
created.
The field itself can optionally have a specified class, meaning that only objects
from this class or one of its subclasses can be assigned to the field.
By default, fields have class "ANY"
. Fields are accessed by reference.
In particular, invoking a method may modify the content of
the fields. Programming for such classes involves writing new methods for a
particular class.
In the R implementation, these methods are R functions, with zero or
more formal arguments.
For standard reference methods, the object itself is not an explicit
argument to the method.
Instead, fields and methods for the class can be referred to by name
in the method definition.
The implementation uses R environments to make fields and other methods
available by name within the method.
Specifically, the parent environment of the method is the object itself.
See the section on “Writing
Reference Methods”.
This special use of environments is optional. If a method is defined
with an initial formal argument .self
, that will be passed in
as the whole object, and the method follows the standard rules for any
function in a package. See the section on “External Methods” The goal of the software described here is to provide a uniform
programming style in R for software dealing with reference classes, whether
implemented directly in R or through an interface to one of the OOP
languages.$methods()
on a generator object g
or as
the argument methods
in a call to setRefClass
.
The two mechanisms have the same effect, but the first makes the code more readable. Methods are written as ordinary R functions but have some special
features and restrictions in their usual form.
In contrast to some other languages (e.g., Python), the object itself
does not need to be an argument in the method definition.
The body of the function can contain calls to any other reference method,
including those inherited from other reference classes and may refer
to methods and to fields in the object by name. Alternatively, a method may be an external method.
This is signalled by .self
being the first formal argument to the method.
The body of the method then works like any ordinary function.
The methods are called like other methods (without the .self
argument, which is supplied internally and always refers to the object
itself).
Inside the method, fields and other methods are accessed in the form
.self$x
.
External methods exist so that reference classes can inherit the
package environment of superclasses
in other packages; see the section on “External Methods”. Fields may be modified in a method by using the
non-local assignment operator, <<-
, as in the $edit
and $undo
methods in the example below.
Note that non-local assignment is required: a local assignment with
the <-
operator just creates a local object in the function
call, as it would in any R function.
When methods are installed, a heuristic check is made for local
assignments to field names and a warning issued if any are detected. Reference methods should be kept simple; if they need to do some
specialized R computation, that computation should use a separate R
function that is called from the reference method.
Specifically, methods can not use special features of the
enclosing environment mechanism, since the method's environment is
used to access fields and other methods.
In particular, methods should not use non-exported entries in the
package's namespace, because the methods may be inherited by a
reference class in another package. Two method names are interpreted specially, initialize
and finalize
. If an initialize
method is defined, it
will be invoked when an object is generated from the class. See the
discussion of method $new(...)
in the section “Initialization Methods”. If a finalize
method is defined, a function will be
registered to invoke it before the environment in
the object is discarded by the garbage collector; finalizers are
registered with atexit=TRUE
, and so are also run at the end of
R sessions. See the matrix viewer example for both initialize and
finalize methods. Reference 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. Two special object names are available.
The entire object can be referred to in a method by the reserved
name .self
.
The object .refClassDef
contains the definition of the
class of the object.
These are accessed as fields but are read-only, with one exception.
In principal, the .self
field can be modified in the $initialize
method, because the object is still being created at this stage.
This is not recommended, as it can invalidate the object with respect
to its class. The methods available include methods inherited from superclasses, as
discussed in the section “Inheritance”. Only methods actually used will be included in the environment
corresponding to an individual object. To declare that a method requires a
particular other method, the first method should include a call
to $usingMethods()
with the name of the other method as an argument.
Declaring the methods this way is essential if the other method is used indirectly (e.g., via sapply()
or do.call()
).
If it is called directly, code analysis will find it.
Declaring the method is harmless in any case, however, and may aid
readability of the source code. Documentation for the methods can be obtained by the $help
method for the generator object.
Methods for classes are not documented in the Rd
format used
for R functions.
Instead, the $help
method prints the calling sequence of the method, followed by
self-documentation from the method definition, in the style of Python.
If the first element of the body of the method is a literal character
string (possibly multi-line), that string is interpreted as documentation.
See the method definitions in the example.$initialize()
,
this method will be called once the reference object has been
created. You should write such a method for a class that needs to do
some special initialization.
In particular, a reference method is recommended rather than a method
for the S4 generic function initialize()
, because some special initialization is
required for reference objects before the initialization of
fields.
As with S4 classes, methods are written for $initialize()
and not for $new()
,
both for the previous reason and also because $new()
is invoked on the generator object and would be a method for that class. The default method for $initialize()
is equivalent to invoking the method $initFields(...)
.
Named arguments assign initial values to the corresponding fields.
Unnamed arguments must be objects from this class or a reference
superclass of this class.
Fields will be initialized to the contents of the fields in such
objects, but named arguments override the corresponding inherited
fields.
Note that fields are simply assigned. If the field is itself a
reference object, that object is not copied.
The new and previous object will share the reference.
Also, a field assigned from an unnamed argument counts as an
assignment for locked fields.
To override an inherited value for a locked field, the new value must
be one of the named arguments in the initializing call.
A later assignment of the field will result in an error. Initialization methods need some care in design.
The generator
for a reference class will be called with no arguments, for example
when copying the object.
To ensure that these calls do not fail, the method must have defaults
for all arguments or check for missing()
.
The method
should include …
as an argument and
pass this on via $callSuper()
(or $initFields()
if
you know that your superclasses have no initialization methods).
This allows future class definitions that subclass this class, with
additional fields.contains=
argument when creating the new class.
The names of the reference superclasses are in slot
refSuperClasses
of the class definition.
Reference classes can inherit from ordinary S4 classes also, but this
is usually a bad idea if it mixes reference fields and non-reference slots.
See the comments in the section on “Implementation”. Class fields are inherited. A class definition can override a field
of the same name in a superclass only if the overriding class is a
subclass of the class of the inherited field. This ensures that a
valid object in the field remains valid for the superclass as well. 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.
The overriding method can call the superclass method by
callSuper(...)
as described below."envRefClass"
.
All reference objects can use the following methods. $callSuper(...)
$callSuper
are passed to the superclass version.
See the matrix viewer class in the example. Note that the intended arguments for the superclass method must be
supplied explicitly; there is no convention for supplying the
arguments automatically, in contrast to the similar mechanism for
functional methods.
$copy(shallow = FALSE)
shallow
is FALSE
, any
field that is itself a reference object will also be copied, and
similarly recursively for its fields. Otherwise, while reassigning a
field to a new reference object will have no side effect, modifying
such a field will still be reflected in both copies of the object.
The argument has no effect on non-reference objects in fields. When
there are reference objects in some fields but it is asserted that
they will not be modified, using shallow = TRUE
will save some
memory and time.
$field(name, value)
name
. With two arguments, the corresponding field is
assigned value
. Assignment checks that name
specifies a
valid field, but the single-argument version will attempt to get
anything of that name from the object's environment. The $field()
method replaces the direct use of a field name, when the name of the
field must be calculated, or for looping over several fields.
$export(Class)
Class
(typically
one of the superclasses of the object's class). Calling the method
has no side effect on the object itself.
$getRefClass()
; $getClass()
$import(value, Class = class(value))
value
into the current object, replacing the
corresponding fields in the current object.
Object value
must come from one of the superclasses of the
current object's class.
If argument Class
is supplied, value
is first coerced to
that class.
$initFields(...)
$initialize()
method. It corresponds to the default initialization for reference
classes. If there are slots and non-reference superclasses, these may
be supplied in the … argument as well. Typically, a specialized $initialize()
method carries out its own computations, then invokes $initFields()
to perform standard initialization, as shown in the
matrixViewer
class in the example below.
$show()
show
function. A general method is
defined for class "envRefClass"
. User-defined reference
classes will often define their own method: see the Example below. Note two points in the example. As with any show()
method, it
is a good idea to print the class explicitly to allow for subclasses
using the method. Second, to call the function show()
from the method, as opposed to the $show()
method itself, refer to methods::show()
explicitly.
$trace(what, ...)
, $untrace(what)
trace
function to the reference method what
. All the arguments of the trace
function can be supplied, except for signature
, which is not
meaningful. The reference method can be invoked on either an object or the
generator for the class. See the section on Debugging below for details.
$usingMethods(...)
$usingMethods()
does nothing at run time.
.self
.refClassDef
"."
, since the
implementation may use such names for special purposes."$"
operator.
The parent of that environment is the namespace of the package in
which the reference class is defined.
Computations in the method have access to all the objects in the
package's namespace, exported or not. When defining a class that contains a reference superclass in another
package, there is an ambiguity about which package namespace should
have that role.
The argument inheritPackage
to setRefClass()
controls
whether the environment of new objects should inherit from an
inherited class in another package or continue to inherit from the
current package's namespace. If the superclass is “lean”, with few methods, or exists
primarily to support a family of subclasses, then it may be better to
continue to use the new package's environment.
On the other hand, if the superclass was originally written as a
standalone, this choice may invalidate existing superclass methods.
For the superclass methods to continue to work, they must use only
exported functions in their package and the new package must import
these. Either way, some methods may need to be written that do not
assume the standard model for reference class methods, but behave
essentially as ordinary functions would in dealing with reference
class objects. The mechanism is to recognize external methods.
An external method is
written as a function in which the first argument, named .self
,
stands for the reference class object.
This function is supplied as the definition for a reference class method.
The method will be called, automatically, with the first argument
being the current object and the other arguments, if any, passed along
from the actual call. Since an external method is an ordinary function in the source code
for its package, it has access to all the objects in the namespace.
Fields and methods in the reference class must be referred to in the
form .self$name
. If for some reason you do not want to use .self
as the first
argument, a function f()
can be converted explicitly as
externalRefMethod(f)
, which returns an object of class
"externalRefMethod"
that can be supplied as a method for the
class.
The first argument will still correspond to the whole object. External methods can be supplied for any reference class, but there is no
obvious advantage unless they are needed.
They are more work to write, harder to read and (slightly) slower to
execute. NOTE: If you are the author of a package whose reference
classes are likely to be subclassed in other packages, you can avoid
these questions entirely by writing methods that only use
exported functions from your package, so that all the methods will
work from another package that imports yours.setRefClass
defines the specified class and
returns a “generator function” object for that class.
This object has class "refObjectGenerator"
; it inherits
from "function"
via "classGeneratorFunction"
and can be
called to generate new objects from the reference class. The returned object is also a reference class object, although not of
the standard construction.
It can be used to invoke reference methods and access fields in the usual way, but
instead of being implemented directly as an environment it has a
subsidiary generator object as a slot, a
standard reference object (of class
"refGeneratorSlot"
).
Note that if one wanted to extend the reference class generator
capability with a subclass, this should be done by subclassing
"refGeneratorSlot"
, not "refObjectGenerator"
. The fields are def
, the class definition, and className
,
the character string name of the class.
Methods generate objects
from the class, to access help on reference methods, and to
define new reference methods for the class.
The currently available methods are:
$new(...)
setRefClass
.
$help(topic)
$methods(...)
methods
argument to setRefClass()
.
Supplying methods in this way, rather than in the call to
setRefClass()
, is recommended for the sake of clearer source
code.
See the section on “Writing Reference Methods” for details. All methods for a class should be defined in the source code that
defines the class, typically as part of a package.
In particular, methods can not be redefined in a class in an attached
package with a namespace: The class method checks for a locked
binding of the class definition. The new methods can refer to any currently defined method by name
(including other methods supplied in this call to
$methods()
.
Note though that previously defined methods are not re-analyzed
meaning that they will not call the new method (unless it redefines an
existing method of the same name). To remove a method, supply NULL
as its new definition.
$fields()
"activeBindingFunction"
.
$lock(...)
$trace(what, ..., classMethod = FALSE)
what
for objects generated
from this class. The generator object tracing works like the
$trace()
method for objects from the class, with two differences.
Since it changes the method definition in the class object itself,
tracing applies to all objects, not just the one on which the trace
method is invoked. Second, the optional argument classMethod = TRUE
allows tracing
on the methods of the generator object itself.
By default, what
is interpreted as the name of a method in the
class for which this object is the generator.
$accessors(...)
abc
by x$getAbc()
and assign it by
x$setAbc(value)
,
the $accessors
method is a convenience function that creates such getter and setter methods for the
specified fields.
Otherwise there is no reason to use this mechanism. In particular, it
has nothing to do with the general ability to define fields by
functions as described in the section on “Reference Objects”.
"environment"
.
Fields correspond to named objects in the environment.
A field associated with a function is implemented as an
active binding.
In particular, fields with a specified class are implemented as a
special form of active binding to enforce valid assignment to the
field. As a related feature, the element in the fields=
list supplied
to setRefClass
can be an accessor
function, a function of one argument that returns
the field if called with no argument or sets it to the value of the
argument otherwise.
Accessor functions are used internally and for inter-system interface
applications, but not generally recommended as they blur the concept
of fields as data within the object. A field, say data
, can be accessed generally by an expression
of the form x$data
for any object from the relevant class.
In a method for this class, the field can be accessed by the name
data
.
A field that is not locked can be set by an expression of the form
x$data <- value
.
Inside a method, a field can be assigned by an expression of the form
x <<- value
.
Note the non-local assignment operator.
The standard R interpretation of this operator works to assign it in
the environment of the object.
If the field has an accessor function defined, getting and setting
will call that function. When a method is invoked on an object, the function defining the method is
installed in the object's environment, with the same environment as the
environment of the function. Note: Slots. Because of the implementation, new reference classes can inherit from
non-reference S4 classes as well as reference classes, and can include
class-specific slots in the definition.
This is usually a bad idea, if the slots from the non-reference
class are thought of as alternatives to fields.
Slots will as always be treated functionally.
Therefore, changes to the slots and the fields will behave inconsistently,
mixing the functional
and reference paradigms for properties of the same object,
conceptually unclear and prone to errors.
In addition, the initialization method for the class will have to sort
out fields from slots, with a good chance of creating anomalous
behavior for subclasses of this class. Inheriting from a class union, however, is a reasonable strategy (with
all members of the union likely to be reference classes).debug
and its
relatives from an object to debug further method invocations on that
object; for example, debug(xx$edit)
. Somewhat more flexible use is available for a reference method version
of the trace
function.
A corresponding $trace()
reference method is available for
either an object or for the reference class generator
(xx$trace()
or mEdit$trace()
in the example below).
Using $trace()
on an object sets up a tracing
version for future invocations of the specified method for that
object.
Using $trace()
on the generator for the class sets up a
tracing version for all future objects from that class (and sometimes for
existing objects from the class if the method is not declared or
previously invoked). In either case, all the arguments to the standard trace
function are available, except for signature=
which is
meaningless since reference methods can not be S4 generic functions.
This includes the typical style trace(what, browser)
for
interactive debugging and trace(what, edit = TRUE)
to edit the
reference method interactively."$"
for this operation; one invokes a method,
m1
say, on an object x
by the expression
x$m1(...)
. Methods in this paradigm 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).
In this document “methods for a class” as opposed to
“methods for a function” will make the distinction. Objects in this paradigm usually have named fields on which
the methods operate.
In the R implementation, the fields are defined when the class is
created.
The field itself can optionally have a specified class, meaning that only objects
from this class or one of its subclasses can be assigned to the field.
By default, fields have class "ANY"
. Fields are accessed by reference.
In particular, invoking a method may modify the content of
the fields. Programming for such classes involves writing new methods for a
particular class.
In the R implementation, these methods are R functions, with zero or
more formal arguments.
For standard reference methods, the object itself is not an explicit
argument to the method.
Instead, fields and methods for the class can be referred to by name
in the method definition.
The implementation uses R environments to make fields and other methods
available by name within the method.
Specifically, the parent environment of the method is the object itself.
See the section on “Writing
Reference Methods”.
This special use of environments is optional. If a method is defined
with an initial formal argument .self
, that will be passed in
as the whole object, and the method follows the standard rules for any
function in a package. See the section on “External Methods” The goal of the software described here is to provide a uniform
programming style in R for software dealing with reference classes, whether
implemented directly in R or through an interface to one of the OOP
languages.$methods()
on a generator object g
or as
the argument methods
in a call to setRefClass
.
The two mechanisms have the same effect, but the first makes the code more readable. Methods are written as ordinary R functions but have some special
features and restrictions in their usual form.
In contrast to some other languages (e.g., Python), the object itself
does not need to be an argument in the method definition.
The body of the function can contain calls to any other reference method,
including those inherited from other reference classes and may refer
to methods and to fields in the object by name. Alternatively, a method may be an external method.
This is signalled by .self
being the first formal argument to the method.
The body of the method then works like any ordinary function.
The methods are called like other methods (without the .self
argument, which is supplied internally and always refers to the object
itself).
Inside the method, fields and other methods are accessed in the form
.self$x
.
External methods exist so that reference classes can inherit the
package environment of superclasses
in other packages; see the section on “External Methods”. Fields may be modified in a method by using the
non-local assignment operator, <<-
, as in the $edit
and $undo
methods in the example below.
Note that non-local assignment is required: a local assignment with
the <-
operator just creates a local object in the function
call, as it would in any R function.
When methods are installed, a heuristic check is made for local
assignments to field names and a warning issued if any are detected. Reference methods should be kept simple; if they need to do some
specialized R computation, that computation should use a separate R
function that is called from the reference method.
Specifically, methods can not use special features of the
enclosing environment mechanism, since the method's environment is
used to access fields and other methods.
In particular, methods should not use non-exported entries in the
package's namespace, because the methods may be inherited by a
reference class in another package. Two method names are interpreted specially, initialize
and finalize
. If an initialize
method is defined, it
will be invoked when an object is generated from the class. See the
discussion of method $new(...)
in the section “Initialization Methods”. If a finalize
method is defined, a function will be
registered to invoke it before the environment in
the object is discarded by the garbage collector; finalizers are
registered with atexit=TRUE
, and so are also run at the end of
R sessions. See the matrix viewer example for both initialize and
finalize methods. Reference 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. Two special object names are available.
The entire object can be referred to in a method by the reserved
name .self
.
The object .refClassDef
contains the definition of the
class of the object.
These are accessed as fields but are read-only, with one exception.
In principal, the .self
field can be modified in the $initialize
method, because the object is still being created at this stage.
This is not recommended, as it can invalidate the object with respect
to its class. The methods available include methods inherited from superclasses, as
discussed in the section “Inheritance”. Only methods actually used will be included in the environment
corresponding to an individual object. To declare that a method requires a
particular other method, the first method should include a call
to $usingMethods()
with the name of the other method as an argument.
Declaring the methods this way is essential if the other method is used indirectly (e.g., via sapply()
or do.call()
).
If it is called directly, code analysis will find it.
Declaring the method is harmless in any case, however, and may aid
readability of the source code. Documentation for the methods can be obtained by the $help
method for the generator object.
Methods for classes are not documented in the Rd
format used
for R functions.
Instead, the $help
method prints the calling sequence of the method, followed by
self-documentation from the method definition, in the style of Python.
If the first element of the body of the method is a literal character
string (possibly multi-line), that string is interpreted as documentation.
See the method definitions in the example.$initialize()
,
this method will be called once the reference object has been
created. You should write such a method for a class that needs to do
some special initialization.
In particular, a reference method is recommended rather than a method
for the S4 generic function initialize()
, because some special initialization is
required for reference objects before the initialization of
fields.
As with S4 classes, methods are written for $initialize()
and not for $new()
,
both for the previous reason and also because $new()
is invoked on the generator object and would be a method for that class. The default method for $initialize()
is equivalent to invoking the method $initFields(...)
.
Named arguments assign initial values to the corresponding fields.
Unnamed arguments must be objects from this class or a reference
superclass of this class.
Fields will be initialized to the contents of the fields in such
objects, but named arguments override the corresponding inherited
fields.
Note that fields are simply assigned. If the field is itself a
reference object, that object is not copied.
The new and previous object will share the reference.
Also, a field assigned from an unnamed argument counts as an
assignment for locked fields.
To override an inherited value for a locked field, the new value must
be one of the named arguments in the initializing call.
A later assignment of the field will result in an error. Initialization methods need some care in design.
The generator
for a reference class will be called with no arguments, for example
when copying the object.
To ensure that these calls do not fail, the method must have defaults
for all arguments or check for missing()
.
The method
should include …
as an argument and
pass this on via $callSuper()
(or $initFields()
if
you know that your superclasses have no initialization methods).
This allows future class definitions that subclass this class, with
additional fields.contains=
argument when creating the new class.
The names of the reference superclasses are in slot
refSuperClasses
of the class definition.
Reference classes can inherit from ordinary S4 classes also, but this
is usually a bad idea if it mixes reference fields and non-reference slots.
See the comments in the section on “Implementation”. Class fields are inherited. A class definition can override a field
of the same name in a superclass only if the overriding class is a
subclass of the class of the inherited field. This ensures that a
valid object in the field remains valid for the superclass as well. 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.
The overriding method can call the superclass method by
callSuper(...)
as described below."envRefClass"
.
All reference objects can use the following methods. $callSuper(...)
$callSuper
are passed to the superclass version.
See the matrix viewer class in the example. Note that the intended arguments for the superclass method must be
supplied explicitly; there is no convention for supplying the
arguments automatically, in contrast to the similar mechanism for
functional methods.
$copy(shallow = FALSE)
shallow
is FALSE
, any
field that is itself a reference object will also be copied, and
similarly recursively for its fields. Otherwise, while reassigning a
field to a new reference object will have no side effect, modifying
such a field will still be reflected in both copies of the object.
The argument has no effect on non-reference objects in fields. When
there are reference objects in some fields but it is asserted that
they will not be modified, using shallow = TRUE
will save some
memory and time.
$field(name, value)
name
. With two arguments, the corresponding field is
assigned value
. Assignment checks that name
specifies a
valid field, but the single-argument version will attempt to get
anything of that name from the object's environment. The $field()
method replaces the direct use of a field name, when the name of the
field must be calculated, or for looping over several fields.
$export(Class)
Class
(typically
one of the superclasses of the object's class). Calling the method
has no side effect on the object itself.
$getRefClass()
; $getClass()
$import(value, Class = class(value))
value
into the current object, replacing the
corresponding fields in the current object.
Object value
must come from one of the superclasses of the
current object's class.
If argument Class
is supplied, value
is first coerced to
that class.
$initFields(...)
$initialize()
method. It corresponds to the default initialization for reference
classes. If there are slots and non-reference superclasses, these may
be supplied in the … argument as well. Typically, a specialized $initialize()
method carries out its own computations, then invokes $initFields()
to perform standard initialization, as shown in the
matrixViewer
class in the example below.
$show()
show
function. A general method is
defined for class "envRefClass"
. User-defined reference
classes will often define their own method: see the Example below. Note two points in the example. As with any show()
method, it
is a good idea to print the class explicitly to allow for subclasses
using the method. Second, to call the function show()
from the method, as opposed to the $show()
method itself, refer to methods::show()
explicitly.
$trace(what, ...)
, $untrace(what)
trace
function to the reference method what
. All the arguments of the trace
function can be supplied, except for signature
, which is not
meaningful. The reference method can be invoked on either an object or the
generator for the class. See the section on Debugging below for details.
$usingMethods(...)
$usingMethods()
does nothing at run time.
.self
.refClassDef
"."
, since the
implementation may use such names for special purposes."$"
operator.
The parent of that environment is the namespace of the package in
which the reference class is defined.
Computations in the method have access to all the objects in the
package's namespace, exported or not. When defining a class that contains a reference superclass in another
package, there is an ambiguity about which package namespace should
have that role.
The argument inheritPackage
to setRefClass()
controls
whether the environment of new objects should inherit from an
inherited class in another package or continue to inherit from the
current package's namespace. If the superclass is “lean”, with few methods, or exists
primarily to support a family of subclasses, then it may be better to
continue to use the new package's environment.
On the other hand, if the superclass was originally written as a
standalone, this choice may invalidate existing superclass methods.
For the superclass methods to continue to work, they must use only
exported functions in their package and the new package must import
these. Either way, some methods may need to be written that do not
assume the standard model for reference class methods, but behave
essentially as ordinary functions would in dealing with reference
class objects. The mechanism is to recognize external methods.
An external method is
written as a function in which the first argument, named .self
,
stands for the reference class object.
This function is supplied as the definition for a reference class method.
The method will be called, automatically, with the first argument
being the current object and the other arguments, if any, passed along
from the actual call. Since an external method is an ordinary function in the source code
for its package, it has access to all the objects in the namespace.
Fields and methods in the reference class must be referred to in the
form .self$name
. If for some reason you do not want to use .self
as the first
argument, a function f()
can be converted explicitly as
externalRefMethod(f)
, which returns an object of class
"externalRefMethod"
that can be supplied as a method for the
class.
The first argument will still correspond to the whole object. External methods can be supplied for any reference class, but there is no
obvious advantage unless they are needed.
They are more work to write, harder to read and (slightly) slower to
execute. NOTE: If you are the author of a package whose reference
classes are likely to be subclassed in other packages, you can avoid
these questions entirely by writing methods that only use
exported functions from your package, so that all the methods will
work from another package that imports yours.setRefClass
defines the specified class and
returns a “generator function” object for that class.
This object has class "refObjectGenerator"
; it inherits
from "function"
via "classGeneratorFunction"
and can be
called to generate new objects from the reference class. The returned object is also a reference class object, although not of
the standard construction.
It can be used to invoke reference methods and access fields in the usual way, but
instead of being implemented directly as an environment it has a
subsidiary generator object as a slot, a
standard reference object (of class
"refGeneratorSlot"
).
Note that if one wanted to extend the reference class generator
capability with a subclass, this should be done by subclassing
"refGeneratorSlot"
, not "refObjectGenerator"
. The fields are def
, the class definition, and className
,
the character string name of the class.
Methods generate objects
from the class, to access help on reference methods, and to
define new reference methods for the class.
The currently available methods are:
$new(...)
setRefClass
.
$help(topic)
$methods(...)
methods
argument to setRefClass()
.
Supplying methods in this way, rather than in the call to
setRefClass()
, is recommended for the sake of clearer source
code.
See the section on “Writing Reference Methods” for details. All methods for a class should be defined in the source code that
defines the class, typically as part of a package.
In particular, methods can not be redefined in a class in an attached
package with a namespace: The class method checks for a locked
binding of the class definition. The new methods can refer to any currently defined method by name
(including other methods supplied in this call to
$methods()
.
Note though that previously defined methods are not re-analyzed
meaning that they will not call the new method (unless it redefines an
existing method of the same name). To remove a method, supply NULL
as its new definition.
$fields()
"activeBindingFunction"
.
$lock(...)
$trace(what, ..., classMethod = FALSE)
what
for objects generated
from this class. The generator object tracing works like the
$trace()
method for objects from the class, with two differences.
Since it changes the method definition in the class object itself,
tracing applies to all objects, not just the one on which the trace
method is invoked. Second, the optional argument classMethod = TRUE
allows tracing
on the methods of the generator object itself.
By default, what
is interpreted as the name of a method in the
class for which this object is the generator.
$accessors(...)
abc
by x$getAbc()
and assign it by
x$setAbc(value)
,
the $accessors
method is a convenience function that creates such getter and setter methods for the
specified fields.
Otherwise there is no reason to use this mechanism. In particular, it
has nothing to do with the general ability to define fields by
functions as described in the section on “Reference Objects”.
"environment"
.
Fields correspond to named objects in the environment.
A field associated with a function is implemented as an
active binding.
In particular, fields with a specified class are implemented as a
special form of active binding to enforce valid assignment to the
field. As a related feature, the element in the fields=
list supplied
to setRefClass
can be an accessor
function, a function of one argument that returns
the field if called with no argument or sets it to the value of the
argument otherwise.
Accessor functions are used internally and for inter-system interface
applications, but not generally recommended as they blur the concept
of fields as data within the object. A field, say data
, can be accessed generally by an expression
of the form x$data
for any object from the relevant class.
In a method for this class, the field can be accessed by the name
data
.
A field that is not locked can be set by an expression of the form
x$data <- value
.
Inside a method, a field can be assigned by an expression of the form
x <<- value
.
Note the non-local assignment operator.
The standard R interpretation of this operator works to assign it in
the environment of the object.
If the field has an accessor function defined, getting and setting
will call that function. When a method is invoked on an object, the function defining the method is
installed in the object's environment, with the same environment as the
environment of the function. Note: Slots. Because of the implementation, new reference classes can inherit from
non-reference S4 classes as well as reference classes, and can include
class-specific slots in the definition.
This is usually a bad idea, if the slots from the non-reference
class are thought of as alternatives to fields.
Slots will as always be treated functionally.
Therefore, changes to the slots and the fields will behave inconsistently,
mixing the functional
and reference paradigms for properties of the same object,
conceptually unclear and prone to errors.
In addition, the initialization method for the class will have to sort
out fields from slots, with a good chance of creating anomalous
behavior for subclasses of this class. Inheriting from a class union, however, is a reasonable strategy (with
all members of the union likely to be reference classes).debug
and its
relatives from an object to debug further method invocations on that
object; for example, debug(xx$edit)
. Somewhat more flexible use is available for a reference method version
of the trace
function.
A corresponding $trace()
reference method is available for
either an object or for the reference class generator
(xx$trace()
or mEdit$trace()
in the example below).
Using $trace()
on an object sets up a tracing
version for future invocations of the specified method for that
object.
Using $trace()
on the generator for the class sets up a
tracing version for all future objects from that class (and sometimes for
existing objects from the class if the method is not declared or
previously invoked). In either case, all the arguments to the standard trace
function are available, except for signature=
which is
meaningless since reference methods can not be S4 generic functions.
This includes the typical style trace(what, browser)
for
interactive debugging and trace(what, edit = TRUE)
to edit the
reference method interactively.## a simple editor for matrix objects. Method $edit() changes some
## range of values; method $undo() undoes the last edit.
mEdit <- setRefClass("mEdit",
fields = list( data = "matrix",
edits = "list"))
## The basic edit, undo methods
mEdit$methods(
edit = function(i, j, value) {
## the following string documents the edit method
'Replaces the range [i, j] of the
object by value.
'
backup <-
list(i, j, data[i,j])
data[i,j] <<- value
edits <<- c(edits, list(backup))
invisible(value)
},
undo = function() {
'Undoes the last edit() operation
and update the edits field accordingly.
'
prev <- edits
if(length(prev)) prev <- prev[[length(prev)]]
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)
})
## A method to automatically print objects
mEdit$methods(
show = function() {
'Method for automatically printing matrix editors'
cat("Reference matrix editor object of class",
classLabel(class(.self)), "\n")
cat("Data: \n")
methods::show(data)
cat("Undo list is of length", length(edits), "\n")
}
)
xMat <- matrix(1:12,4,3)
xx <- mEdit(data = xMat)
xx$edit(2, 2, 0)
xx
xx$undo()
mEdit$help("undo")
stopifnot(all.equal(xx$data, xMat))
utils::str(xx) # show fields and names of methods
## A method to save the object
mEdit$methods(
save = function(file) {
'Save the current object on the file
in R external object format.
'
base::save(.self, file = file)
}
)
tf <- tempfile()
xx$save(tf)
## Not run: ------------------------------------
# ## Inheriting a reference class: a matrix viewer
# mv <- setRefClass("matrixViewer",
# fields = c("viewerDevice", "viewerFile"),
# contains = "mEdit",
# methods = list( view = function() {
# dd <- dev.cur(); dev.set(viewerDevice)
# devAskNewPage(FALSE)
# matplot(data, main = paste("After",length(edits),"edits"))
# dev.set(dd)},
# edit = # invoke previous method, then replot
# function(i, j, value) {
# callSuper(i, j, value)
# view()
# }))
#
# ## initialize and finalize methods
# mv$methods( initialize =
# function(file = "./matrixView.pdf", ...) {
# viewerFile <<- file
# pdf(viewerFile)
# viewerDevice <<- dev.cur()
# dev.set(dev.prev())
# callSuper(...)
# },
# finalize = function() {
# dev.off(viewerDevice)
# })
#
# ## debugging an object: call browser() in method $edit()
# xx$trace(edit, browser)
#
# ## debugging all objects from class mEdit in method $undo()
# mEdit$trace(undo, browser)
## ---------------------------------------------
<!-- %$ -->
Run the code above in your browser using DataLab