Janko Thyson
2014-Nov-15 14:49 UTC
[R] Fine controlling "three dots" argument dispatch to functions with identical argument names
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]]
Jeff Newmiller
2014-Nov-15 16:26 UTC
[R] Fine controlling "three dots" argument dispatch to functions with identical argument names
AFAIK You have to alter the name of at least one of the y arguments as used by
foobar, and anyone calling foobar has to read about that in the help file. That
is only one y can be in "...". e.g.
foobar <- function( x, y_foo, ... ) {
foo( x, y=y_foo, ... )
bar( x, ... )
}
---------------------------------------------------------------------------
Jeff Newmiller The ..... ..... Go Live...
DCN:<jdnewmil at dcn.davis.ca.us> Basics: ##.#. ##.#. Live
Go...
Live: OO#.. Dead: OO#.. Playing
Research Engineer (Solar/Batteries O.O#. #.O#. with
/Software/Embedded Controllers) .OO#. .OO#. rocks...1k
---------------------------------------------------------------------------
Sent from my phone. Please excuse my brevity.
On November 15, 2014 6:49:41 AM PST, Janko Thyson <janko.thyson at
gmail.com> wrote:>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]]
>
>______________________________________________
>R-help at r-project.org mailing list
>https://stat.ethz.ch/mailman/listinfo/r-help
>PLEASE do read the posting guide
>http://www.R-project.org/posting-guide.html
>and provide commented, minimal, self-contained, reproducible code.