Match.Call with Default Arguments

match.call with default arguments

Hopefully, this doesn't lead to dragons.

foo <- function(x=NULL,y=NULL,z=2) {
mget(names(formals()),sys.frame(sys.nframe()))

}

foo(x=4)

$x
[1] 4

$y
NULL

$z
[1] 2

print(foo(x=4))

$x
[1] 4

$y
NULL

$z
[1] 2

Setting default arguments to `...`

I think this one calls for do.call(). Notice I have renamed your default arguments x and y to match those for arguments 1 and 2 in plot(). If you want to continue to use a and b, uncomment the fourth line. But it will make things a lot easier if you stick with the default names.

simpleFun <- function(x, y, ...) {
args <- as.list(match.call()[-1])
if(!any(names(args) == "xlim"))
args$xlim <- c(-6, 6)
## names(args)[1:2] <- c("x", "y")
do.call("plot", args)
}

This seems to work fine on these sample runs.

simpleFun2(a = rnorm(10), b = rnorm(10))
simpleFun2(a = rnorm(10), b = rnorm(10), xlim = c(-1, 1))
simpleFun2(a = rnorm(10), b = rnorm(10), xlim = c(-1, 1), ylim = c(-4, 4))

Call function with dots arguments and default value in another function with dots arguments and default value

@Onyambu replied in the comments. But I want to put his answer here hoping that it can help someone.

f<- function(x, y, z = 3, ...){
x*y*z
}
g <- function(w = 4, ...){
w*f(...)
}
g(w = 2, x = 1, y = 5)
[1] 30

Default argument depending of the function matched in R

1) Try redefining table and xtabs in newfun. Ensure that fun is calling the local versions by converting it to character and using do.call.

newfun <- function(..., fun) {
table <- function(x, ..., useNA = "ifany") base::table(x, ..., useNA = useNA)
xtabs <- function(x, ..., na.action = NULL, addNA = NULL)
stats::xtabs(x, ..., na.action = na.action, addNA = addNA)
fun <- deparse(substitute(fun))
do.call(fun, list(...))
}

newfun(warpbreaks[-1], fun = table)
newfun(breaks ~ ., warpbreaks, fun = xtabs)

2) Another approach is to have 3 functions, one for your version of table, one for your version of xtabs and then one to contain the common code which each of the others would call. That may be more straight forward than (1).

mytable <- function(..., useNA = "ifany") {
tab <- table(..., useNA = useNA)
other(tab)
tab
}

myxtabs <- function(..., na.action = NULL, addNA = TRUE) {
tab <- xtabs(..., na.action = na.action, addNA = addNA)
other(tab)
tab
}

other <- function(x) {
# code
}

How to explicitly call the default value of a function argument in R?

You can access the argument list and default values via:

> formals(rnorm)
$n

$mean
[1] 0

$sd
[1] 1

formals("rnorm") also works. Some simple examples:

> rnorm(10,mean = formals(rnorm)$mean)
[1] -0.5376897 0.4372421 0.3449424 -0.9569394 -1.1459726 -0.6109554 0.1907090 0.2991381 -0.2713715
[10] -1.4462570
> rnorm(10,mean = formals(rnorm)$mean + 3)
[1] 2.701544 2.863189 1.709289 2.987687 2.848045 5.136735 2.559616 3.827967 3.079658 5.016970

Obviously, you could store the result of formals(rnorm) ahead of time as well.

getting the arguments of a parent function in R, with names

get_args <- function()
{
cl <- sys.call(-1)
f <- get(as.character(cl[[1]]), mode="function", sys.frame(-2))
cl <- match.call(definition=f, call=cl)
as.list(cl)[-1]
}

The key here is to set the definition argument to match.call to be get_arg's calling function. This should (hopefully!) work for the general case where get_args can be called from anywhere.

Compilation error when calling function with default arguments

That's not how default arguments work. The default argument has to go in the declaration, not the definition:

// foo.h
void foo(int, int, int = 5); // default values here

// foo.cpp
void foo(int a, int b, int c)
{
// ...
}

Think about it: Every TU that wants to use the function has to know the default value. This only makes sense in the declaration, which every user of the function must see.

Why is match.call useful?

One reason that is relevant here is that match.call captures the language of the call without evaluating it, and in this case it allows lm to treat some of the "missing" variables as "optional". Consider:

lm(x ~ y, data.frame(x=1:10, y=runif(10)))

Vs:

lm2 <- function (
formula, data, subset, weights, na.action, method = "qr",
model = TRUE, x = FALSE, y = FALSE, qr = TRUE, singular.ok = TRUE,
contrasts = NULL, offset, ...
) {
mf <- model.frame(
formula = formula, data = data, subset = subset, weights = weights
)
}
lm2(x ~ y, data.frame(x=1:10, y=runif(10)))
## Error in model.frame.default(formula = formula, data = data, subset = subset, :
## invalid type (closure) for variable '(weights)'

In lm2, since weights is "missing" but you still use it in weights=weights, R tries to use the stats::weights function which is clearly not what was intended. You could get around this by testing for missingness before you call model.frame, but at that point the match.call starts looking pretty good. Look at what happens if we debug the call:

debug(lm2)
lm2(x ~ y, data.frame(x=1:10, y=runif(10)))
## debugging in: lm2(x ~ y, data.frame(x = 1:10, y = runif(10)))
## debug at #5: {
## mf <- model.frame(formula = formula, data = data, subset = subset,
## weights = weights)
## }
Browse[2]> match.call()
## lm2(formula = x ~ y, data = data.frame(x = 1:10, y = runif(10)))

match.call doesn't involve the missing arguments at all.

You could argue that the optional arguments should have been made explicitly optional via default values, but that's not what happened here.



Related Topics



Leave a reply



Submit