[Rd] [Q] Get formal arguments of my implemented S4 method
John Chambers
jmc at r-project.org
Thu Jan 29 19:06:43 CET 2015
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
More information about the R-devel
mailing list