[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