I'm struggling with a problem that is acknowledged but for which I have yet to find an easy solution: how to catch misspecified arguments passed through to R functions, when the function definition includes the ellipsis or three dots ...
.
As stated in Wickham's Advanced R:
Using
...
comes at a price — any misspelled arguments will not raise an error, and any arguments after...
must be fully named. This makes it easy for typos to go unnoticed.
Here's an example:
myfun <- function(x, ...)
UseMethod("myfun")
myfun.character <- function(x, toLower = FALSE, ...)
cat("Sent and transformed by myfun:", ifelse(toLower, tolower(x), x), "\n")
myfun("Test String with CaPiTaLs.")
## Sent and transformed by myfun: Test String with CaPiTaLs.
myfun("Test String with CaPiTaLs.", toLower = TRUE)
## Sent and transformed by myfun: test string with capitals.
myfun("Test String with CaPiTaLs.", tolower = TRUE)
## Sent and transformed by myfun: Test String with CaPiTaLs.
myfun("Test String with CaPiTaLs.", toLower = TRUE, notDefined = 1)
## Sent and transformed by myfun: test string with capitals.
Here, the subtle misspelling of toLower
causes no visible error except the failure of the output to be lower case, as the user probably expected. In the last example, arguments that the user thought would be functional are not, but they simply disappear into the ether because of the nature of ...
.
Of course I could inspect the contents of ...
through list(...)
, but I am wondering if there is a better way, linked to the formals defined in the function or those to which ...
is passed.
And by the way, does anyone know what we should be calling the ...
? I am nearly sure I saw a reference with a name in the Julia docs but cannot find this now!
Added:
Ideally I'd like to figure out the best way to generate an error if an argument is not something that ought to be passed through in the ellipsis, when something in the scope of the called function passed through the ellipsis to a subsidiary argument. For instance, how best to trap these errors:
myfun2 <- function(x, ...)
UseMethod("my fun")
myfun2.character <- function(x, toLower = FALSE, ...)
cat("Sent and transformed by myfun:", ifelse(toLower, tolower(x), x), "\n", ...)
myfun2("Test String with CaPiTaLs.", tolower = TRUE)
## Sent and transformed by myfun: Test String with CaPiTaLs.
## TRUE
myfun2("Test String with CaPiTaLs.", toLower = TRUE, notDefined = 1)
## Sent and transformed by myfun: test string with capitals.
## 1
myfun2("Test String with CaPiTaLs.", sep = "\tXX\t")
## Sent and transformed by myfun: XX Test String with CaPiTaLs. XX