[Rd] Using substitute from inside an S4 method
bill@insightful.com
bill at insightful.com
Wed Jan 25 21:37:06 CET 2006
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."
More information about the R-devel
mailing list