--- title: "S3 Method Lookup" author: "Kurt Hornik" date: 2019-08-19 categories: ["Internals", "User-visible Behavior"] tags: ["S3 method lookup"] ---
At the core of the S3 object system as introduced in the White Book lies
the idea that (S3) methods are ordinary functions that follow the
GEN.CLS
naming convention (with GEN.default
as a final fallback).
In the initial R implementation of this object system, these methods
were searched for in the environment (and all enclosing environments)
from which the generic was called.
With the advent of namespaces (see Tierney (2003), “Name space
management for R”, R News, 3(1):2-6) a mechanism for registering S3
methods via S3method()
directives in the NAMESPACE
file of a package
was added. Using S3method(GEN, CLS)
or S3method(GEN, CLS, FUN)
registers function named, respectively, GEN.CLS
or FUN
for dispatch
without the need for exporting it. Using the latter (3-argument)
directive allows to bypass the GEN.CLS
naming convention. The generic
used in the registration is that “as seen from the package”, and hence
needs to be available when the namespace is loaded. This registration
mechanism is available for all packages (as they all have a namespace),
but not in script code (outside of packages).
Initially, the S3 registry would be consulted only when no appropriate
method was found in the calling environment. Methods in base
traditionally all follow follow the GEN.CLS
naming convention and
hence were not registered, as they would be found in .BaseNamespaceEnv
as the last element of the static part of the package namespace
environments, and hence ahead of the search path starting with the
global environment (.GlobalEnv
, the user’s workspace) and ending with
the base environment (.BaseEnv
). However, all registered methods
could be shadowed by GEN.CLS
exports in attached packages (found on
the search path ahead of the registry). To make S3 lookup both more
safe and more efficient, it was changed in R 3.5.0 to use the registry
after the top level environment (see ?topenv
) of the calling
environment. Alongside, all S3 methods in base are now registered as
well.
Since R 3.6.0, S3method()
directives in NAMESPACE
can also be used
to perform delayed S3 method registration. With S3method(PKG::GEN, CLS, FUN)
function FUN
will get registered as an S3 method for class
CLS
and generic GEN
from package PKG
only when the namespace of
PKG
is loaded. This can be employed to deal with situations where the
method is not “immediately” needed, and having to pre-load the namespace
of pkg
(and all its strong dependencies) in order to perform immediate
registration is considered too “costly”.
Since c76951 in the trunk (committed on 2019-08-10), there is a
.S3method()
function for registering S3 methods in scripts. Again,
this allows to register methods named differently than GEN.CLS
.
With all these registration enhancements in place, finding S3 methods
via the search path, between .GlobalEnv
and .BaseEnv
, is no longer
necessary, and hence with c77043 in the trunk (committed on 2019-08-19)
is turned off by default. This is currently controllable via an
internal environment variable, which will disappear eventually, as
relying on such in-between search path lookups is both unsafe and
inefficient. This may seem to be a major change: but in fact, the CRAN
regular checks have been performed with in-between search path lookups
turned off for more than a year now, and all check issues stemming from
this change have long been eliminated. Similarly, Bioconductor will
have all missing S3 method registrations added to its packages for the
upcoming 3.10 release.