[Rd] Pb with lapply()
Martin Maechler
maechler at stat.math.ethz.ch
Fri Feb 1 09:50:23 CET 2008
>>>>> "HP" == Herve Pages <hpages at fhcrc.org>
>>>>> on Thu, 31 Jan 2008 10:26:31 -0800 writes:
HP> Hi, If needed, lapply() tries to convert its first
HP> argument into a list before it starts doing something
HP> with it:
>> lapply
HP> function (X, FUN, ...)
HP> {
HP> FUN <- match.fun(FUN)
HP> if (!is.vector(X) || is.object(X))
HP> X <- as.list(X)
HP> .Internal(lapply(X, FUN))
HP> }
HP> But in practice, things don't always seem to "work" as suggested by
HP> this code (at least to the eyes of a naive user).
Yes. That is the infamous problem of what I'd call a mental conflict
between namespaces and function-centered OOP (as in S3 or S4),
or put differently, the problem that not all R functions are
S4 generics right from the start :
Both lapply() and as.list() are in the base namespace.
Consequently, lapply() will always call base::as.list() and
unfortunately base::as.list() is not becoming an S4 generic by your
>> setClass("A", representation(data="list"))
HP> [1] "A"
>> setMethod("as.list", "A", function(x, ...) x at data)
HP> Creating a new generic function for "as.list" in ".GlobalEnv"
HP> [1] "as.list"
See: it's an S4 generic only in .GlobalEnv, but to really work
it should be an S4 generic in base.
HP> Seems like using force() inside lapply() would solve the problem:
Well, it's not force() that makes it work,
it's the fact that you define a version of lapply outside "base"
and that of course does see your as.list() generic in .GlobalEnv ..
HP> lapply2 <- function(X, FUN, ...)
HP> {
HP> FUN <- match.fun(FUN)
HP> if (!is.vector(X) || is.object(X))
HP> X <- force(as.list(X))
HP> .Internal(lapply(X, FUN))
HP> }
HP> It works now:
[...........]
Now one "solution" to the problem is to redefine base::as.list()
to be your S4 generic. Most smart useRs I know would call this
a terrible hack though...
and yes, I'm guilty of committing that hack -- inside the Matrix package,
not for as.list() but for as.matrix():
The consequence of that is that e.g. eigen() *does* work for
all our matrices, because eigen starts with as.matrix() and that
needs to work as a proper (i.e. S4) generic in order to work as
it should.
A much better solution to the underlying deeper problem would be
to find a way where ___ conceptually ___ part (or all of)
'methods' would be inside of 'base', and as.list(), as.matrix()
etc all S4 (and S3 simultaneously) generics.
[and we have pondered of using 'base4' for that,
which would contain part of current base and part of current methods;
but there have been different ideas].
One workaround/solution used recently (notably for the group generics)
was to make more of these functions into
*primitive* functions with C-internal S3 and S4 method dispatch.
That maybe a desideratum for "now".
Martin Maechler, ETH Zurich (and R core team)
More information about the R-devel
mailing list