[R] Fine controlling "three dots" argument dispatch to functions with identical argument names
Janko Thyson
janko.thyson at gmail.com
Sat Nov 15 15:49:41 CET 2014
Dear list,
I wonder if there's a clever way to fine control the exact way arguments
are dispatched via R's "three dots" argument ....
Consider the following use case:
- you have a function foobar() that calls foo() which in turn calls bar()
- *both* foo() and bar() have an argument that's called y, but they each
have a *different meaning*
- in the call to foobar(), you would like to say "here's the y for foo()
and here's the y for bar()". *That's what I would like to accomplish*.
If you simply call foobar(x = "John Doe", y = "hello world"), y only get's
dispatched to foo() as in the call to bar() things would have to be
explicit in order to be dispatched (i.e. the call would have to be bar(x =
x, y = y) instead of bar(x = x, ...):
foo <- function(x, y = "some character", ...) {
message("foo ----------")
message("foo/threedots")
try(print(list(...)))
message("foo/y")
try(print(y))
bar(x = x, ...)}
bar <- function(x, y = TRUE, ...) {
message("bar ----------")
message("bar/threedots")
try(print(list(...)))
message("bar/y")
try(print(y))
return(paste0("hello: ", x))}
foobar <- function(x, ...) {
message("foobar ----------")
message("foobar/threedots")
try(print(list(...)))
foo(x = x, ...)}
foobar(x = "John Doe", y = "hi there")# foobar ----------#
foobar/threedots# $y# [1] "hi there"# # foo ----------# foo/threedots#
list()# foo/y# [1] "hi there"# bar ----------# bar/threedots# list()#
bar/y# [1] TRUE# [1] "hello: John Doe"
What I conceptionally would like to be able to do is something like this:
foobar(x = "John Doe", y_foo = "hello world!", y_bar = FALSE)
Here's an approach that works but that also feels very odd:
foo <- function(x, y = "some character", ...) {
message("foo ----------")
message("foo/threedots")
try(print(list(...)))
message("foo/y")
arg <- paste0("y_", sys.call()[[1]])
if (arg %in% names(list(...))) {
y <- list(...)[[arg]]
}
try(print(y))
bar(x = x, ...)}
bar <- function(x, y = TRUE, ...) {
message("bar ----------")
message("bar/threedots")
try(print(list(...)))
message("bar/y")
arg <- paste0("y_", sys.call()[[1]])
if (arg %in% names(list(...))) {
y <- list(...)[[arg]]
}
try(print(y))
return(paste0("hello: ", x))}
foobar(x = "John Doe", y_foo = "hello world!", y_bar = FALSE)# foobar
----------# foobar/threedots# $y_foo# [1] "hello world!"# # $y_bar#
[1] FALSE# # foo ----------# foo/threedots# $y_foo# [1] "hello
world!"# # $y_bar# [1] FALSE# # foo/y# [1] "hello world!"# bar
----------# bar/threedots# $y_foo# [1] "hello world!"# # $y_bar# [1]
FALSE# # bar/y# [1] FALSE# [1] "hello: John Doe"
How would you go about implementing something like this?
I also played around with S4 method dispatch to see if I could define
methods for a signature argument ..., but that didn't go too well (and it's
probably a very bad idea anyway):
setGeneric(
name = "foo",
signature = c("x", "..."),
def = function(x, ...) standardGeneric("foo") )
setMethod(
f = "foo",
signature = signature(x = "character", "..." = "MyThreeDotsForBar"),
definition = function(x, ...) bar(x = x))## --> does not work
[[alternative HTML version deleted]]
More information about the R-help
mailing list