setClass               package:methods               R Documentation

_C_r_e_a_t_e _a _C_l_a_s_s _D_e_f_i_n_i_t_i_o_n

_D_e_s_c_r_i_p_t_i_o_n:

     Create  a class definition, specifying the representation (the
     slots) and/or the classes contained in this one (the
     superclasses), plus other optional details.

_U_s_a_g_e:

     setClass(Class, representation, prototype, contains=character(),
              validity, access, where, version, sealed, package,
              S3methods = FALSE)

_A_r_g_u_m_e_n_t_s:

   Class: character string name for the class.

representation: a named list of the slots that the new class should
          have, the names giving the names of the slots and the
          corresponding elements being the character string names of 
          the corresponding classes. Usually a call to the
          'representation' function. 

          Backward compatibility and compatibility with S-Plus allows
          unnamed elements for superclasses, but the recommended style
          is to use the 'contains=' argument instead.

prototype: an object providing the default data for the slots in this
          class.  Usually and preferably the result of a call to
          'prototype'. 

contains: what classes does this class extend?  (These are called
          _superclasses_ in some languages.)  When these classes have
          slots, all their slots will be contained in the new class as
          well. 

   where: the environment in which to store or remove the definition. 
          Defaults to the top-level environment of the calling function
          (the global environment for ordinary computations, and the
          environment or name space of a package in the source code for
          that package). 

validity: if supplied, should be a validity-checking method for objects
          from this class (a function that returns 'TRUE' if its
          argument is a valid object of this class and one or more
          strings describing the failures otherwise).  See
          'validObject' for details.

access, version: access and version, included for compatibility with
          S-Plus, but currently ignored.

  sealed: if 'TRUE', the class definition will be sealed, so that
          another call to 'setClass' will fail on this class name. 

 package: an optional package name for the class.  By default (and
          usually) the name of the package in which the class
          definition is assigned. 

S3methods: if 'TRUE', S3 methods may be written for this class.  S3
          generic functions and primitives will dispatch an S3 method
          defined for this class, given an S4 object from the class or
          from a subclass of it, provided no S4 method and no more 
          direct S3 method is found.  Writing S3 methods for S4 classes
          is somewhat deprecated (see Methods), but if you do write
          them, the class should be created with this argument 'TRUE',
          so inheritance will work.  By default, the current
          implementation takes no special action, so that methods will
          be dispatched for this class but _not_ for subclasses.  Note
          that future versions may revoke this and dispatch no S3
          methods other than the default unless 'S3methods' is 'TRUE'. 

_B_a_s_i_c _U_s_e: _S_l_o_t_s _a_n_d _I_n_h_e_r_i_t_a_n_c_e:

     The two essential arguments, other than the class name are
     'representation' and 'contains', defining the explicit slots and
     the inheritance (superclasses). Together, these arguments define
     all the information in an object from this class; that is, the
     names of all the slots and the classes required for each of them.

     The name of the class determines which methods apply directly to
     objects from this class.  The  inheritance information specifies
     which methods apply indirectly, through inheritance.  See Methods.

     The slots in a class definition will be the union of all the slots
     specified directly by 'representation' and all the slots in all
     the contained classes. There can only be one slot with a given
     name; specifically, the direct and inherited slot names must be
     unique. That does not, however, prevent the same class from being
     inherited via more than one path.

     One kind of element in the 'contains=' argument is special,
     specifying one of the R object types or one of a few other special
     R types ('matrix' and 'array'). See the section on inheriting from
     object types, below.

     Certain slot names are not allowed in the current implementation,
     as they correspond to attributes which are treated specially. 
     These are 'class', 'comment', 'dim', 'dimnames', 'names',
     'row.names' and 'tsp'. Some other slot names have special meaning;
     these names start with the '"."' character.  To be safe, you
     should define all of your own slots with names starting with an
     alphabetic character.

_I_n_h_e_r_i_t_i_n_g _f_r_o_m _O_b_j_e_c_t _T_y_p_e_s:

     In addition to containing other S4 classes, a class definition can
     contain either an S3 class (see the next section) or a built-in R
     pseudo-class-one of the R object types or one of the special R
     pseudo-classes '"matrix"' and '"array'.  A class can contain at
     most one of the object types, directly or indirectly. When it
     does, that contained class determines the "data part" of the
     class.

     Objects from the new class try to inherit the built in behavior of
     the contained type. In the case of normal R data types, including
     vectors, functions and expressions, the implementation is
     relatively straightforward. For any object 'x' from the class,
     'typeof(x)' will be the contained basic type; and a special
     pseudo-slot, '.Data', will be shown with the corresponding class.
     See the '"numWithId"' example below.

     For an object from any class that does _not_ contain such a type,
     'typeof(x)' will be '"S4"'.

     Some R data types do not behave normally, in the sense that they
     are non-local references or other objects that are not duplicated.
     Examples include those corresponding to classes '"environment"',
     '"externalptr"', and '"name"'. These can not be the types for
     objects with user-defined classes (either S4 or S3) because
     setting an attribute overwrites the object in all contexts. It is
     possible to define a class that inherits from such types, through
     an indirect mechanism that stores the inherited object in a
     reserved slot. The implementation tries to make such classes
     behave as if the object had a data part of the corresponding
     object type. Methods defined with the object type in the signature
     should work as should core code that coerces an object to the type
     in an internal or primitive calculation. There is no guarantee,
     however, because C-level code may switch directly on the object
     type, which in this case will be '"S4"'. The cautious mechanism is
     to use 'as(x, "environment")' or something similar before doing
     the low-level computation.  See the example for class
     '"stampedEnv"' below.

     Also, keep in mind that the object passed to the low-level
     computation will be the underlying object type, _without_ any of
     the slots defined in the class. To return the full information,
     you will usually have to define a method that sets the data part.

     Note that, in the current implementation, the interpretation of
     the '".Data"' pseudo-slot includes all of the object types above,
     as well as the special pseudo-classes '"matrix"' and '"array',
     which R treats internally as if they were object types (they have
     no explicit class and 'is.object' returns 'FALSE' for such
     objects). Some of this implementation is still experimental, so a
     wise policy is to use standard tools, such as 'as(object, type)',
     to convert to the underlying data type, rather than the
     pseudo-slot, when possible.

_I_n_h_e_r_i_t_i_n_g _f_r_o_m _S_3 _C_l_a_s_s_e_s:

     Old-style S3 classes have no formal definition.  Objects are
     "from" the class when their class attribute contains the character
     string considered to be the class name.

     Using such classes with formal classes and methods is necessarily
     a risky business, since there are no guarantees about the content
     of the objects or about consistency of inherited methods. Given
     that, it is still possible to define a class that inherits from an
     S3 class, providing that class has been registered as an old class
     (see 'setOldClass'). The essential result is that S3 method
     dispatch will use the S3 class as registered when dispatching.

     Some additional options are planned, to control whether the object
     is converted to an S3 class before dispatch.  In the present
     implementation, it is not, which causes some S3 computations to
     misbehave, since they are not seeing the S3 class explicitly.

_C_l_a_s_s_e_s _a_n_d _P_a_c_k_a_g_e_s:

     Class definitions normally belong to packages (but can be defined
     in the  global environment as well, by evaluating the expression
     on the command line or in a file sourced from the command line).
     The corresponding package name is part of the class definition;
     that is, part of the 'classRepresentation' object holding that
     definition.  Thus, two classes with the same name can exist in
     different packages, for most purposes.

     When a class name is supplied for a slot or a superclass, a
     corresponding class definition will be found, looking from the
     name space or environment of the current package, assuming the
     call to 'setClass' in question appears directly in the source for
     the package.  That's where it should appear, to avoid ambiguity.

     In particular, if the current package has a name space then the 
     class must be found in the current package itself, in the imports
     defined by that name space, or in the base package.

     When this rule does not identify a class uniquely (because it
     appears in more than one imported package) then the 'packageSlot'
     of the character string name needs to be supplied with the name.
     This should be a rare occurrence.

_R_e_f_e_r_e_n_c_e_s:

     Chambers, John M. (2008) _Software for Data Analysis: Programming
     with R_ Springer.  (For the R version.)

     Chambers, John M. (1998) _Programming with Data_ Springer (For the
     original S4 version.)

_S_e_e _A_l_s_o:

     'Classes' for a general discussion of classes, 'Methods' for an
     analogous discussion of methods, 'makeClassRepresentation'

_E_x_a_m_p_l_e_s:

     ## A simple class with two slots
     setClass("track",
              representation(x="numeric", y="numeric"))
     ## A class extending the previous, adding one more slot
     setClass("trackCurve",
         representation(smooth = "numeric"),
         contains = "track")
     ## A class similar to "trackCurve", but with different structure
     ## allowing matrices for the "y" and "smooth" slots
     setClass("trackMultiCurve",
              representation(x="numeric", y="matrix", smooth="matrix"),
              prototype = list(x=numeric(), y=matrix(0,0,0),
                               smooth= matrix(0,0,0)))
     ##
     ## Suppose we want trackMultiCurve to be like trackCurve when there's
     ## only one column.
     ## First, the wrong way.
     try(setIs("trackMultiCurve", "trackCurve",
         test = function(obj) {ncol(slot(obj, "y")) == 1}))

     ## Why didn't that work?  You can only override the slots "x", "y",
     ## and "smooth" if you provide an explicit coerce function to correct
     ## any inconsistencies:

     setIs("trackMultiCurve", "trackCurve",
       test = function(obj) {ncol(slot(obj, "y")) == 1},
       coerce = function(obj) {
          new("trackCurve",
              x = slot(obj, "x"),
              y = as.numeric(slot(obj,"y")),
              smooth = as.numeric(slot(obj, "smooth")))
       })

     ## A class that extends the built-in data type "numeric"

     setClass("numWithId", representation(id = "character"),
              contains = "numeric")

     new("numWithId", 1:3, id = "An Example")

     ## inherit from reference object of type "environment"
     setClass("stampedEnv", contains = "environment",
           representation(update = "POSIXct"))

     e1 <- new("stampedEnv", new.env(), update = Sys.time())

     setMethod("[[<-", c("stampedEnv", "character", "missing"),
        function(x, i, j, ..., value) {
            ev <- as(x, "environment")
            ev[[i]] <- value  #update the object in the environment
            x@update <- Sys.time() # and the update time
            x})

     e1[["noise"]] <- rnorm(10)

