Re: [Rd] Using substitute from inside an S4 method

From: <bill_at_insightful.com>
Date: Wed 25 Jan 2006 - 20:37:06 GMT

On Wed, 25 Jan 2006, Seth Falcon wrote:

> I would like to access the name of a variable passed to an S4 method.
> For a function, I would do this:
>
> f <- function(x) as.character(substitute(x))
>
> This also works for a the examples I have tried for methods that do
> not have extra, non-dispatch args:
>
> setGeneric("A", function(x, ...) standardGeneric("A"))
>
> setMethod("A", signature(x="character"),
> function(x) as.character(substitute(x)))
>
> However, I'm seeing strange behavior if the method uses an extra
> argument:
>
> setMethod("A", signature(x="numeric"),
> function(x, y) as.character(substitute(x)))
>
> num <- 1
>
> A(num)
> [1] "x"
>
> A(num, 2)
> [1] "x"
>
> Is there a way to make this work? I came up with one workaround that
> uses a non-standard generic (see below).
>
> It seems that when a method uses extra args matching '...' in the
> generic, an extra frame is used in the evaluation and so substitute()
> isn't reaching the same place as without extra args.

The reason you get an extra frame is that when the method's argument doesn't match the generic's, setMethod makes a function with the generic's argument list that calls your method (renamed ".local") and makes that new function the real method. E.g.,

   > setMethod("A",sig=signature(x="character"), function(x,n){

          if(nchar(x)>n) stop("nchar(x)>n")
          deparse(substitute(x))
     })

   [1] "A"
   > getMethod("A",sig=signature(x="character"))    Method Definition:

   function (x, ...)
   {

       .local <- function (x, n)
       {
           if (nchar(x) > n)
               stop("nchar(x)>n")
           deparse(substitute(x))
       }
       .local(x, ...)

   }
   ...

This has 2 bothersome side effects. One is yours:

   > A(paste("One","Two"), 10)
   [1] "x"
and the other is that the function mentioned in the error report is misleading:

   > A("xyz", 1)
   Error in .local(x, ...) : nchar(x)>n
You can workaround both problems by making a method that looks somewhat like the the one generated by setMethod but gets some details right for your function. E.g.,

   > setMethod("A",sig=signature(x="character"),

          function(x, ...) {
             A.character <- function(x,n,x.name){
                 if(nchar(x)>n) stop("nchar(x)>n")
                 x.name
             }
             x.name <- deparse(substitute(x))
             A.character(x, ..., x.name=x.name)
          }
     )

This gives a suggestive function name in the error message

   > A(paste("One","Two"), 3)
   Error in A.character(x, ..., x.name = x.name) :

        nchar(x)>n
and lets you use substitute:

   > A(paste("One","Two"), 10)
   [1] "paste(\"One\", \"Two\")"
Thus you don't have to guess how many frames or environments lie between your method and the generic.

This works in R and Splus.



Bill Dunlap
Insightful Corporation
bill at insightful dot com
360-428-8146

 "All statements in this message represent the opinions of the author and do  not necessarily reflect Insightful Corporation policy or position."



R-devel@r-project.org mailing list
https://stat.ethz.ch/mailman/listinfo/r-devel Received on Thu Jan 26 07:42:56 2006

This archive was generated by hypermail 2.1.8 : Fri 27 Jan 2006 - 09:47:38 GMT