Defaults of function argument which name correspond to existing function name


Is there a way to prevent a promise already under evaluation error when

  1. you want the name of a function argument to be the name of an existing function
  2. and you want to set a default for this particular argument
  3. and you want to be able to call the outer function with its defaults only (i.e. without the need to pass an explicit value to each argument)?

In my example below, while foo(1:5, bar) works, foo(1:5) throws such an error.

Of course I could go and change the argument name from bar to, say, bar_fun, but I would rather stick with the actual function's name if possible.

foo <- function(x, bar = bar) {
  bar(x)
}
bar <- function(x) {
  UseMethod("bar")
}
bar.default <- function(x) {
  sum(x)
}
foo(1:5)
#> Error in foo(1:5): promise already under evaluation: recursive default argument reference or earlier problems?
foo(1:5, bar)
#> [1] 15

Motivation (first order)

The real-world use case is that bar() is actually settings(), a function which returns a list of settings. I'd like to version those settings. So there'd be e.g. methods like settings.v1, settings.v2, ..., and settings.default. And I thought of using settings.default to define the "runtime version" of settings to use, so e.g.:

settings <- function(x) {
  UseMethod("settings")
}

settings.v1 <- function(x) {
  list(system = "dev")
}

settings.v2 <- function(x) {
  list(system = "production")
}

settings.default <- function(x) {
  settings.v2(
}

foo <- function(x, settings = settings) {
  settings()
}

foo()
#> Error in foo(): promise already under evaluation: recursive default argument reference or earlier problems?
foo(settings = settings)
#> $system
#> [1] "production"

Since settings.default() calls the settings method I want to use, it'd be great if I could just call foo() with its defaults (which would then always pick up the settings.default() method).

Motivation (second order)

I'm experimenting with adhering more to principles of functional programming (see e.g. chapter from Advanced R or wikipedia link) and its distinction of pure and effectful/side-effecty functions.

Previously, I probably would have implemented settings via some sort of a global variable that thus each foo() had access to, so I could be lazy and not define it as an argument of function foo(), but foo() then would depend on things outside of its scope - which is a very bad thing in FP.

Now I want to at least state the dependency of foo() on my settings by handing it a function that returns the settings values - which is sort of my lazyness at least complying to some extend with top-level FP principles.

Of course the non-lazy (and arguably best) solution would be to carefully state all actual settings dependencies one by one as function arguments in foo(), e.g. foo(settings_system = settings()$system) ;-)

- - Source

Answers

answered 1 week ago G. Grothendieck #1

1) Try explicitly getting it from the parent:

foo <- function(x, bar = get("bar", 1)) {
  bar(x)
}

2) Another possibility is to use an argument name such as bar.. The user can still write foo(1:15, bar = whatever), e.g. any of these three calls work:

foo <- function(x, bar. = bar) {
  bar.(x)
}

foo(1:5)
foo(1:5, bar) 
foo(1:5, bar = bar)

comments powered by Disqus