rguides

do.call

do.call evaluates a function call constructed with call(). The primary use case is passing arguments stored in a list, programmatically constructing function calls, or dynamically dispatching to functions by name.

Signature

do.call(what, args, quote = FALSE, envir = parent.frame())

Arguments:

  • what — a function, or a character string naming a function to call
  • args — a list or pairlist of arguments to pass to the function
  • quote — if TRUE, args is treated as an unevaluated expression (Language object)
  • envir — the environment in which to evaluate the call

Returns: The result of calling what with the provided arguments.

How do.call Relates to call()

call() constructs a call object without evaluating it. do.call() evaluates that call.

# call() builds the unevaluated expression
call("mean", x = 1:10)
# => mean(x = 1:10)

# do.call() evaluates it
do.call("mean", list(x = 1:10))
# => 5.5

call() alone does not run the function — it returns a Language object. do.call() is what actually fires the function.

Basic Usage

Pass arguments as a named list:

do.call("paste", list("a", "b", sep = "-"))
# => "a-b"

Works with any function, including built-ins and user-defined:

my_summary <- function(x, na.rm = TRUE) {
  c(mean = mean(x, na.rm = na.rm),
    sd = sd(x, na.rm = na.rm))
}

do.call(my_summary, list(1:10, na.rm = TRUE))
# => mean 5.5, sd 3.03

Constructing Calls Dynamically

Building Arguments from a List

When arguments are stored in a list, do.call is cleaner than using do.call(..., envir = ) alternatives:

args <- list(1, 2, 3)
do.call("+", args)
# => 6

Using do.call with User Functions

The args list must be named if your function expects named arguments:

calculate <- function(operation, x, y) {
  switch(operation,
    add = x + y,
    multiply = x * y)
}

do.call(calculate, list(operation = "add", x = 3, y = 4))
# => 7

Combining with match.call

A powerful pattern captures the call in a function and replays it with do.call:

wrapper <- function(f, data, ...) {
  call_obj <- match.call()
  call_obj[[1]] <- as.name("do.call")
  call_obj$f <- as.name(f)
  eval(call_obj)
}

# This builds and runs do.call(f, list(data, ...))

do.call vs Direct Calling

The difference is only visible when arguments live in a list:

# Direct call:
result <- mean(c(1, 2, 3))

# Equivalent with do.call:
result <- do.call(mean, list(c(1, 2, 3)))

do.call is necessary when the arguments must be collected or manipulated as data:

args <- split(mtcars$mpg, mtcars$cyl)
do.call(rbind, args)

Here rbind() gets called with all the list elements as separate arguments — something impossible to write directly without do.call.

Common Use Cases

Apply a Function to Split Data

results <- do.call(rbind, lapply(split(mtcars, mtcars$gear), function(df) {
  data.frame(gear = df$gear[1], mean_mpg = mean(df$mpg))
}))

Dynamic Function Dispatch

operations <- list(
  mean = function(x) base::mean(x),
  median = function(x) stats::median(x)
)

op <- "median"
do.call(operations[[op]], list(1:10))
# => 5.5

Building a Call from Components

func_name <- "t.test"
args <- list(x = rnorm(100), y = rnorm(100), var.equal = TRUE)
do.call(func_name, args)

See Also