First, I mentioned that I believe that the idiomatic way to do this is to build a challenge and then evaluate it. See the write.csv example. I believe that this code will do what you want using this method.
wrapper <- function(X, arg, ...) { force(X)
Ok, now here is an attempt to explain the problems you discovered. I'm ready to fix too, but hopefully this will at least help clarify the issues, as @idfah did.
First, Iโll deal with the problem of โdefaults,โ because I find it easier. I think this can be done easier, as in the following two functions, where the second ( f2 ) just calls the first ( f1 ). We see that the default argument in f1 overridden by the promise x in f2 , and when this promise is evaluated, it is missing. The moral of this story (I think); the default values โโmust be set again in your calling function, if this variable is included in the call.
f1 <- function(x=1) {print(match.call()); x} f2 <- function(x) {f1(x=x)} f1()
Now about the flaw in lapply . Here I basically have sgibb code, but you added a message about whether the arg argument is considered absent. We have what seems like a curious contradiction; the message says that arg NOT missing, but when the function tries to access it, we get an error message telling us that arg IS is missing.
.add <- function(x, arg) { print(match.call()) if(missing(arg)) { message("arg is missing in .add") x } else { message("arg is not missing") x + arg } } wrapper <- function(l, arg) {lapply(l, .add, arg=arg)} wrapper(1)
I think lapply puts the arg promise in ..1 , so it doesn't look absent, but when it tries to evaluate it, it discovers that it is absent. The moral of this story (I think); do not try to pass passes through lapply .
UPDATE: More precisely, this is what the dot scan extension works with. Consider this version of lapply (which actually doesn't work on the list, but otherwise has the same code style); this shows that we are getting the same behavior.
apply3 <- function(X, FUN, ...) { print(match.call()) FUN(X, ...) } wrapper3 <- function(l, arg) {apply3(l, .add, arg=arg)} wrapper3(1)
But when we substitute the dots with the variable name, it works as expected.
apply4 <- function(X, FUN, hm) { print(match.call()) FUN(X, hm) } wrapper4 <- function(l, arg) {apply4(l, .add, hm=arg)} wrapper4(1)
And one more example; if I use the dots, but I will do the extension myself by calling directly ..1 , it also works! This is curious, since the consistent call is the same as the version that is not working.
apply3b <- function(X, FUN, ...) { print(match.call()) FUN(X, ..1) } wrapper3b <- function(l, arg) {apply3b(l, .add, arg=arg)} wrapper3b(1)