[Q] Get formal arguments of my implemented S4 method
Some experimenting is needed. But I think a subclass is likely to be cleaner. The official model is that methods and generic differ only in the body, so having an object-based way to say that some methods are non-conforming feels more natural to me.
On Jan 29, 2015, at 9:57 AM, Michael Lawrence <lawrence.michael at gene.com> wrote:
Would we really need the special class or would simply checking the formals of the method against those of the generic be simple and fast enough? On Thu, Jan 29, 2015 at 9:41 AM, John Chambers <jmc at r-project.org> wrote:
I wouldn't want to add more to the current approach; if someone would like to devote some time, the much preferable idea IMO would be to replace the whole mechanism. Here's one suggestion: 1. have a class, say "nonConformingMethod" for method definitions that diverge in the argument list. 2. the internal dispatch code checks the class of the selected definition (this can likely be done with little cost in the standard case). In the case of non-conforming, the arguments are rematched to define the method's other arguments. The possibilities need examining, but my feeling is that the re-matching should happen in the current frame, as opposed to doing a new call. There is a fair amount of code, for example in callNextMethod, that requires some computations using knowledge of the current mechanism. If at some point we required re-installing all packages using non-conforming methods, that code could be made simpler and faster. John On Jan 29, 2015, at 8:08 AM, William Dunlap <wdunlap at tibco.com> wrote:
I wish it didn't have to depend on the name '.local'. Back when I wrote a lot of S4 methods I avoided the auto-generated .local and named the local function something that made sense so that is was
easier
for a user to track down the source of an error.
E.g., define the generic QQQ with numeric and integer methods:
setGeneric("QQQ",
function(x, ...)NULL)
setMethod("QQQ",
signature=signature(x="numeric"),
function(x, lower, ...) {
if (x<lower) stop("x<lower")
})
setMethod("QQQ",
signature=signature(x="integer"),
function(x, ...) {
.QQQ.integer <- function(x, lower, ...) if (x<lower)
stop("x<lower")
.QQQ.integer(x, ...)
})
and try using them:
QQQ(3.4, 10)
Error in .local(x, ...) : x<lower
traceback()
4: stop("x<lower") at #4
3: .local(x, ...)
2: QQQ(3.4, 10)
1: QQQ(3.4, 10)
QQQ(3L, 10)
Error in .QQQ.integer(x, ...) : x<lower
traceback()
4: stop("x<lower") at #4
3: .QQQ.integer(x, ...) at #5
2: QQQ(3L, 10)
1: QQQ(3L, 10)
I think the latter gives the user more guidance on how to fix the
problem.
Perhaps instead of searching for an assignment to '.local' you could search for an assignment to the name of the function used in the last function call of the method. Bill Dunlap TIBCO Software wdunlap tibco.com On Thu, Jan 29, 2015 at 6:34 AM, Hadley Wickham <h.wickham at gmail.com>
wrote:
On Thu, Jan 29, 2015 at 7:57 AM, John Chambers <jmc at r-project.org>
wrote:
On Jan 28, 2015, at 6:37 PM, Michael Lawrence <
lawrence.michael at gene.com> wrote:
At this point I would just due: formals(body(method)[[2L]]) At some point we need to figure out what to do with this .local()
confusion.
Agreed, definitely. The current hack is to avoid re-matching
arguments on method dispatch, so a fix would need to be fairly deep in the implementation.
But I don't think the expression above is quite right.
body(method)[[2L]] is the assignment. You need to evaluate the rhs.
Here is a function that does the same sort of thing, and returns the
standard formals for the generic if this method does not have nonstandard arguments. We should probably add a version of this function for 3.3.0, so user code doesn't have hacks around the current hack.
methodFormals <- function(f, signature = character()) {
fdef <- getGeneric(f)
method <- selectMethod(fdef, signature)
genFormals <- base::formals(fdef)
b <- body(method)
if(is(b, "{") && is(b[[2]], "<-") && identical(b[[2]][[2]],
as.name(".local"))) {
local <- eval(b[[2]][[3]])
if(is.function(local))
return(formals(local))
warning("Expected a .local assignment to be a function.
Corrupted method?")
} genFormals }
I have similar code in roxygen2: # When a generic has ... and a method adds new arguments, the S4 method # wraps the definition inside another function which has the same
arguments
# as the generic. This function figures out if that's the case, and
extracts
# the original function if so.
#
# It's based on expression processing based on the structure of the
# constructed method which looks like:
#
# function (x, ...) {
# .local <- function (x, ..., y = 7) {}
# .local(x, ...)
# }
extract_method_fun <- function(x) {
fun <- x at .Data
method_body <- body(fun)
if (!is.call(method_body)) return(fun)
if (!identical(method_body[[1]], quote(`{`))) return(fun)
first_line <- method_body[[2]]
if (!is.call(first_line)) return(fun)
if (!identical(first_line[[1]], quote(`<-`))) return(fun)
if (!identical(first_line[[2]], quote(`.local`))) return(fun)
first_line[[3]]
}
--
http://had.co.nz/
______________________________________________ R-devel at r-project.org mailing list https://stat.ethz.ch/mailman/listinfo/r-devel
[[alternative HTML version deleted]]
______________________________________________ R-devel at r-project.org mailing list https://stat.ethz.ch/mailman/listinfo/r-devel
[[alternative HTML version deleted]]
______________________________________________ R-devel at r-project.org mailing list https://stat.ethz.ch/mailman/listinfo/r-devel