class(x)
returns a plain character string. Code
that needs to distinguish, say, the definition of a class in a
particular namespace has nothing to go on.
The proposed extension is to allow the class slot of an arbitrary object to contain something other than a plain character string. If the class of the class slot extends "character", there is in fact nothing needed to allow the change, the problem is just to ensure that the extended class slot is preserved and used.
Specifically, the notion is to have a class, say
"objectLocator"
, that adds to the name of an object
some slots that identify where the object is located:
getClass()
; this needs, in effect, to have methods
for the relevant types of class slot. Because
getClass()
will end up being central to everything,
much of this will need to be coded internally for speed.
The current definition of getClass()
uses a
(global) table of stored class definitions. That will be
removed; a revised version of the methods package is currently
(7/17/03) being tested that uses only class definitions stored
in the corresponding package environments, no global tables.
new()
needs to be modified to use the
environment of the calling function as the starting point in
looking for the definition of a class specified as character
string. (It will also take the extended forms of class locator
objects as well; in practice, a suitable definition of
getClass()
may well do the right thing
automatically, if new()
passes down the calling
environment as a default search environment.)
setClass()
, the
prototype object created will have a class slot "pointing" to
the corresponding package (and environment?). As a result,
instances of the class created by new()
should
contain the appropriate class slot.
Other class-based utilities will need to be modified to also allow the
appropriate version of a class to be used (e.g,. is()
and
as()
).
Details will be important, but the general picture seems similar to
that for new()
: provide the environment of the calling
function as the default, but with the possibility that the class
"name" will override in the call to getClass()
.
f
is a generic
function and package P
defines methods for
f
, then a call to f
from a function in the
package sees the methods in P
(including whatever P
imports).
But if f
is visible globally, then a call to
f
from the global environment sees only the methods that
are exported from the currently attached packages.
The methods in P
may or not be exported.
The current dispatch mechanism is quite close to this model, except
for primitive functions. These are a problem, in that dispatch is
done from C without any generic function being visible, so some
additional mechanism is needed.
Details:
f
in the
environment of the generic function. So long as the correct
version of f
is found, and so long as the methods
list is computed correctly with respect to the environment of
that function, the dispatch should work correctly.
The current implementation amortizes the cost of computing the
methods lists by waiting until f
is called to merge
the visible methods. There seems no obvious problem with
retaining that strategy.
f
with the appropriate versions of its
methods would have to exist (at least) in the namespace of P
and in one of the environments on the search list so both calls
to f
would find the correct methods.
(Where on the search list? I think in the environment of the
first attached package that contains either the generic function
or a setMethod()
call for that function. Included
here is the notion that in S a non-generic definition of
f
is implicitly equivalent to a
setGeneric()
call and a specification of the
default method.)
setMethod()
and setGeneric()
should
honor the extended object locator class(es) used for
getClass()
, to allow multiple generics of the same
name on different packages.
A global C table contains a flag for the third check and the corresponding methods list object, indexed by the internal codes for the primitive functions. (Strictly speaking this is not a global table, but a table that would belong to the "current evaluator", if the evaluator was an object.)
To maintain current efficiency for the non-methods calls to the primitives, it seems that the global table needs to be retained, but without containing the methods definitions themselves. This implies that the three checks will pass if methods are defined for this primitive in any currently active package, whether the methods are exported or not.
The actual implementation of shadow versions of the generics, or of special methods list objects, appears feasible in a couple of different ways: the differences don't seem very important. The simplest mechanism seems to be hidden (e.g., name-mangled) generic function objects operating just like non-primitive generics, except that they are not the function objects visible when the primitive is called.