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