On Sun, Jun 13, 2010 at 6:58 PM, John Chambers <jmc at r-project.org>
wrote:> A general goal for the next version of R is to make S4 and S3 play better
> together.
>
> As mentioned in a previous thread, one limitation has been that S3 generic
> functions, specifically the UseMethod() call, did not make use of S4
> inheritance when dispatching on general S4 objects.
>
> This has been fixed in a version committed today (updated to rev 52267).
> ?The code change is not large, but it has some general implications.
Mainly,
> in applying S3 generic functions to objects from S4 classes, the default
> recommendation is to define an S3 method for the class, when possible, and
> then set that definition to be the S4 method as well.
>
> The section "Methods for S3 Generic Functions" of the ?Methods
documentation
> in the (new) version has details and points to examples. The text of that
> section is appended below.
>
> John
>
> =====================> Methods for S3 Generic Functions:
>
> ? ? S4 methods may be wanted for functions that also have S3 methods,
> ? ? corresponding to classes for the first formal argument of an S3
> ? ? generic function-either a regular R function in which there is a
> ? ? call to the S3 dispatch function, 'UseMethod', or one of a
fixed
> ? ? set of primitive functions, which are not true functions but go
> ? ? directly to C code. In either case S3 method dispatch looks at the
> ? ? class of the first argument or the class of either argument in a
> ? ? call to one of the primitive binary operators. S3 methods are
> ? ? ordinary functions with the same arguments as the generic function
> ? ? (for primitives the formal arguments are not actually part of the
> ? ? object, but are simulated when the object is printed or viewed by
> ? ? 'args()'). The "signature" of an S3 method is
identified by the
> ? ? name to which the method is assigned, composed of the name of the
> ? ? generic function, followed by '"."', followed by the
name of the
> ? ? class. For details, see S3Methods.
>
> ? ? To implement a method for one of these functions corresponding to
> ? ? S4 classes, there are two possibilities: either an S4 method or an
> ? ? S3 method with the S4 class name. The S3 method is only possible
> ? ? if the intended signature has the first argument and nothing else.
> ? ? In this case, the recommended approach is to define the S3 method
> ? ? and also supply the identical function as the definition of the S4
> ? ? method. If the S3 generic function was 'f3(x, ...)' and the S4
> ? ? class for the new method was '"myClass"':
>
> ? ? f3.myClass <- function(x, ...) { ..... }
> ? ? setMethod("f3", "myClass", f3.myClass)
>
> ? ? The reasons for defining both S3 and S4 methods are as follows:
>
> ? ? ? 1. An S4 method alone will not be seen if the S3 generic
> ? ? ? ? ?function is called directly. ?However, primitive functions
> ? ? ? ? ?and operators are exceptions: The internal C code will look
> ? ? ? ? ?for S4 methods if and only if the object is an S4 object. ?In
> ? ? ? ? ?the examples, the method for '`[`' for class
'"myFrame"' will
> ? ? ? ? ?always be called for objects of this class.
>
> ? ? ? ? ?For the same reason, an S4 method defined for an S3 class
> ? ? ? ? ?will not be called from internal code for a non-S4 object.
> ? ? ? ? ?(See the example for function 'Math' and class
'"data.frame"'
> ? ? ? ? ?in the examples.)
>
> ? ? ? 2. An S3 method alone will not be called if there is _any_
> ? ? ? ? ?eligible non-default S4 method. (See the example for function
> ? ? ? ? ?'f3' and class '"classA"' in the
examples.)
>
> ? ? Details of the selection computations are given below.
>
> ? ? When an S4 method is defined for an existing function that is not
> ? ? an S4 generic function (whether or not the existing function is an
> ? ? S3 generic), an S4 generic function will be created corresponding
> ? ? to the existing function and the package in which it is found
> ? ? (more precisely, according to the implicit generic function either
> ? ? specified or inferred from the ordinary function; see
> ? ? 'implicitGeneric'). A message is printed after the initial call
to
> ? ? 'setMethod'; this is not an error, just a reminder that you
have
> ? ? created the generic. Creating the generic explicitly by the call
>
> ? ? 'setGeneric("f3")'
>
> ? ? avoids the message, but has the same effect. The existing function
> ? ? becomes the default method for the S4 generic function. Primitive
> ? ? functions work the same way, but the S4 generic function is not
> ? ? explicitly created (as discussed below).
>
> ? ? S4 and S3 method selection are designed to follow compatible rules
> ? ? of inheritance, as far as possible. S3 classes can be used for any
> ? ? S4 method selection, provided that the S3 classes have been
> ? ? registered by a call to 'setOldClass', with that call
specifying
> ? ? the correct S3 inheritance pattern. S4 classes can be used for any
> ? ? S3 method selection; when an S4 object is detected, S3 method
> ? ? selection uses the contents of 'extends(class(x))' as the
> ? ? equivalent of the S3 inheritance (the inheritance is cached after
> ? ? the first call).
>
> ? ? An existing S3 method may not behave as desired for an S4
> ? ? subclass, in which case utilities such as 'asS3' and
'S3Part' may
> ? ? be useful. ?If the S3 method fails on the S4 object, 'asS3(x)'
may
> ? ? be passed instead; if the object returned by the S3 method needs
> ? ? to be incorporated in the S4 object, the replacement function for
> ? ? 'S3Part' may be useful, as in the method for class
'"myFrame"' in
> ? ? the examples.
>
> ? ? Here are details explaining the reasons for defining both S3 and
> ? ? S4 methods. Calls still accessing the S3 generic function directly
> ? ? will not see S4 methods, except in the case of primitive
> ? ? functions. This means that calls to the generic function from
> ? ? namespaces that import the S3 generic but not the S4 version will
> ? ? only see S3 methods. On the other hand, S3 methods will only be
> ? ? selected from the S4 generic function as part of its default
> ? ? ('"ANY"') method. If there are inherited S4
non-default methods,
> ? ? these will be chosen in preference to _any_ S3 method.
>
> ? ? S3 generic functions implemented as primitive functions (including
> ? ? binary operators) are an exception to recognizing only S3 methods.
> ? ? These functions dispatch both S4 and S3 methods from the internal
> ? ? C code. There is no explicit generic function, either S3 or S4.
> ? ? The internal code looks for S4 methods if the first argument, or
> ? ? either of the arguments in the case of a binary operator, is an S4
> ? ? object. If no S4 method is found, a search is made for an S3
> ? ? method.
>
> ? ? S4 methods can be defined for an S3 generic function and an S3
> ? ? class, but if the function is a primitive, such methods will not
> ? ? be selected if the object in question is not an S4 object. In the
> ? ? examples below, for instance, an S4 method for signature
> ? ? '"data.frame"' for function 'f3()' would be
called for the S3
> ? ? object 'df1'. A similar S4 method for primitive function
'`[`'
> ? ? would be ignored for that object, but would be called for the S4
> ? ? object 'mydf1' that inherits from
'"data.frame"'. Defining both an
> ? ? S3 and S4 method removes this inconsistency.
Would like to see one or more examples of this that one can enter into
R and run.