On Sun, Jun 13, 2010 at 6:58 PM, John Chambers <j...@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. ______________________________________________ R-devel@r-project.org mailing list https://stat.ethz.ch/mailman/listinfo/r-devel