The key point here is that setGeneric("unique") is done that way, without other argument, whoever does it. That creates the generic from the implicit generic corresponding to base::unique. If package A had done anything else, the resulting methods tables would NOT refer to package "base" but to package "PkgA" and it's that version of the generic that would need to be imported.

So it's not particularly relevant that we're dealing with PkgA::unique() if the generic function was created from base::unique by the standard call. That's what would make an automatic imputation of the generic from importMethods() possible.

On 12/16/11 2:57 PM, Martin Morgan wrote:
On 12/16/2011 12:19 PM, John Chambers wrote:
The subject heading is correct if referring to exportMethods() and
importMethodsFrom(). They refer to the methods tables, not the generic
functions, whatever the extensions manual says.

Looking into the code of namespaceImportMethods() will illustrate this.
It just deals with lists of method tables obtained from .getGenerics()
which in spite of its name also only looks for the method table metadata
objects.

As I vaguely recall, there was some concern at one time about having
extra copies of the generic version of the function.

The fundamental problem is that creating methods for unique(), say, does
not change the way calls to base::unique() work. Therefore, all packages
that want to use methods have to ensure that a generic version of unique
gets in between. Primitive functions are an exception because the method
dispatch is in the C code and has a rule for checking when given an S4
object. There is no corresponding provision for evaluating a call to a
regular function.

If the importing package has a setGeneric() for the relevant function
then its own namespace has the generic version of the function. (That is
a workaround, but I inferred that was what you were trying to avoid.)

Fixes seem possible, but some care is needed. If exportMethods
automatically exported the generic function, it really is no different
from export() for that function.

export() somehow implies ownership of the generic, e.g., responsibility
for documentation. I can see in the scenario below that PkgB might be
expected to Depends: PkgA if it intends for the user to access PkgB's
methods on PkgA::unique.

namespaceImportMethods() could try to supply the generic function if it
is not already present. If it does not find the generic in the namespace
being imported, it would essentially have to call setGeneric(), assuming
the non-generic function exists in the specified package (e.g., in base
for unique()).

In the example below for PkgC the 'unique' generic is in PkgB's
namespace imports

 > getNamespaceImports("PkgB")
$base
[1] TRUE

$PkgA
unique
"unique"

I guess PkgB could have Depends: PkgA, not importFrom(PkgA, unique), and
then defined and exported a method on PkgA::unique found on the search
path, so that the generic wasn't available to PkgC. But I'd be happy if
the generic found in either PkgB's namespace or namespace imports were
imported along with the method. Not sure that I like the idea of calling
setGeneric() -- PkgA could have done something non-standard -- and would
rather an error.

Thans for your attention.

Martin


Comments?
John



On 12/16/11 6:16 AM, Martin Morgan wrote:
tar of Pkgs A, B, C attached. Martin

On 12/15/2011 03:34 PM, Martin Morgan wrote:
In

> R.version.string
[1] "R Under development (unstable) (2011-12-15 r57901)"

section 1.6.6 of 'Writing R Extensions' says

Note that exporting methods on a generic in the namespace will
also export the generic, and exporting a generic in the
namespace will also export its methods.

and

Note that importMethodsFrom will also import any generics defined in
the namespace on those methods

However, if PkgA promotes 'unique' to a generic and exports that

DESCRIPTION:
Imports: methods

R/f.R:
setGeneric("unique")

NAMESPACE:
export(unique)

and PkgB creates and exports a method on unique

DESCRIPTION
Imports: methods, PkgA

R/f.R:
setClass("B", representation(b="numeric"))
setMethod(unique, "B",
function(x, incomparables=FALSE, ...) unique(x@b))

NAMESPACE:
importFrom(PkgA, unique)
exportClasses(B)
exportMethods(unique)

and PkgC wants to import PkgB's classes and methods

DESCRIPTION
Imports: methods, PkgB

R/f.R
cunique <- function(x) unique(x)

NAMESPACE
importMethodsFrom(PkgB, unique)
export(cunique)

then

(a) the 'unique' generic is not available to the user of PkgB

> library(PkgB)
> unique(new("B", b=1:5))
Error in unique.default(new("B", b = 1:5)) :
unique() applies only to vectors

and (b) the generic has not been imported to PkgC's namespace

> cunique(new("B", b=1:5))
Error in unique.default(b) : unique() applies only to vectors

A workaround is for PkgB to also export(unique), and for PkgC to also
importFrom(PkgA, unique), but is this the intention?

This is arising from Bioconductor efforts to place commonly promoted
functions and S3 classes into a single package, to avoid conflicts when
the same function is promoted independently by several packages.

Martin





______________________________________________
R-devel@r-project.org mailing list
https://stat.ethz.ch/mailman/listinfo/r-devel

Reply via email to