Normally, you invoke a R function by typing arguments manually. A powerful alternative is to call a function with a list of arguments assembled programmatically. This is the purpose of invoke().

invoke(.fn, .args = list(), ..., .env = caller_env(), .bury = c(".fn",
  ""))

Arguments

.fn

A function to invoke. Can be a function object or the name of a function in scope of .env.

.args, ...

List of arguments (possibly named) to be passed to .fn.

.env

The environment in which to call .fn.

.bury

A character vector of length 2. The first string specifies which name should the function have in the call recorded in the evaluation stack. The second string specifies a prefix for the argument names. Set .bury to NULL if you prefer to inline the function and its arguments in the call.

Details

Technically, invoke() is basically a version of base::do.call() that creates cleaner call traces because it does not inline the function and the arguments in the call (see examples). To achieve this, invoke() creates a child environment of .env with .fn and all arguments bound to new symbols (see env_bury()). It then uses the same strategy as eval_bare() to evaluate with minimal noise.

Life cycle

invoke() is in questioning lifecycle stage. Now that we understand better the interaction between unquoting and dots capture, we believe that invoke() should not take a .args argument. Instead it should take dots with dots_list() in order to enable !!! syntax.

We ask rlang users not to use invoke() in CRAN packages because we plan a breaking API update to remove the .args argument.

Examples

# invoke() has the same purpose as do.call(): invoke(paste, letters)
#> [1] "a b c d e f g h i j k l m n o p q r s t u v w x y z"
# But it creates much cleaner calls: invoke(call_inspect, mtcars)
#> .fn(mpg = `1`, cyl = `2`, disp = `3`, hp = `4`, drat = `5`, wt = `6`, #> qsec = `7`, vs = `8`, am = `9`, gear = `10`, carb = `11`)
# and stacktraces: fn <- function(...) sys.calls() invoke(fn, list(mtcars))
#> [[1]] #> pkgdown::build_site() #> #> [[2]] #> build_reference(pkg, lazy = FALSE, examples = examples, run_dont_run = run_dont_run, #> mathjax = mathjax, seed = seed, path = file.path(path, "reference"), #> depth = 1L, preview = FALSE) #> #> [[3]] #> purrr::map(topics, build_reference_topic, path, pkg = pkg, lazy = lazy, #> depth = depth, examples = examples, run_dont_run = run_dont_run, #> mathjax = mathjax) #> #> [[4]] #> .f(.x[[i]], ...) #> #> [[5]] #> data_reference_topic(topic, pkg, path = path, examples = examples, #> run_dont_run = run_dont_run, mathjax = mathjax, depth = depth) #> #> [[6]] #> as_data(tags$tag_examples[[1]], env = new.env(parent = globalenv()), #> topic = tools::file_path_sans_ext(topic$file_in), path = path, #> examples = examples, run_dont_run = run_dont_run, depth = depth) #> #> [[7]] #> as_data.tag_examples(tags$tag_examples[[1]], env = new.env(parent = globalenv()), #> topic = tools::file_path_sans_ext(topic$file_in), path = path, #> examples = examples, run_dont_run = run_dont_run, depth = depth) #> #> [[8]] #> purrr::pmap_chr(list(code = code, run = run, show = show), format_example_chunk, #> env = child_env(env), path = path, topic = topic, obj_id = id_generator$id) #> #> [[9]] #> .f(code = .l[[c(1L, 1L)]], run = .l[[c(2L, 1L)]], show = .l[[c(3L, #> 1L)]], ...) #> #> [[10]] #> evaluate::evaluate(code, env, new_device = TRUE) #> #> [[11]] #> evaluate_call(expr, parsed$src[[i]], envir = envir, enclos = enclos, #> debug = debug, last = i == length(out), use_try = stop_on_error != #> 2L, keep_warning = keep_warning, keep_message = keep_message, #> output_handler = output_handler, include_timing = include_timing) #> #> [[12]] #> timing_fn(handle(ev <- withCallingHandlers(withVisible(eval(expr, #> envir, enclos)), warning = wHandler, error = eHandler, message = mHandler))) #> #> [[13]] #> handle(ev <- withCallingHandlers(withVisible(eval(expr, envir, #> enclos)), warning = wHandler, error = eHandler, message = mHandler)) #> #> [[14]] #> try(f, silent = TRUE) #> #> [[15]] #> tryCatch(expr, error = function(e) { #> call <- conditionCall(e) #> if (!is.null(call)) { #> if (identical(call[[1L]], quote(doTryCatch))) #> call <- sys.call(-4L) #> dcall <- deparse(call)[1L] #> prefix <- paste("Error in", dcall, ": ") #> LONG <- 75L #> msg <- conditionMessage(e) #> sm <- strsplit(msg, "\n")[[1L]] #> w <- 14L + nchar(dcall, type = "w") + nchar(sm[1L], type = "w") #> if (is.na(w)) #> w <- 14L + nchar(dcall, type = "b") + nchar(sm[1L], #> type = "b") #> if (w > LONG) #> prefix <- paste0(prefix, "\n ") #> } #> else prefix <- "Error : " #> msg <- paste0(prefix, conditionMessage(e), "\n") #> .Internal(seterrmessage(msg[1L])) #> if (!silent && identical(getOption("show.error.messages"), #> TRUE)) { #> cat(msg, file = outFile) #> .Internal(printDeferredWarnings()) #> } #> invisible(structure(msg, class = "try-error", condition = e)) #> }) #> #> [[16]] #> tryCatchList(expr, classes, parentenv, handlers) #> #> [[17]] #> tryCatchOne(expr, names, parentenv, handlers[[1L]]) #> #> [[18]] #> doTryCatch(return(expr), name, parentenv, handler) #> #> [[19]] #> withCallingHandlers(withVisible(eval(expr, envir, enclos)), warning = wHandler, #> error = eHandler, message = mHandler) #> #> [[20]] #> withVisible(eval(expr, envir, enclos)) #> #> [[21]] #> eval(expr, envir, enclos) #> #> [[22]] #> eval(expr, envir, enclos) #> #> [[23]] #> invoke(fn, list(mtcars)) #> #> [[24]] #> .fn(`1`) #>
# Compare to do.call(): do.call(call_inspect, mtcars)
#> (function (...) #> match.call())(mpg = c(21, 21, 22.8, 21.4, 18.7, 18.1, 14.3, 24.4, #> 22.8, 19.2, 17.8, 16.4, 17.3, 15.2, 10.4, 10.4, 14.7, 32.4, 30.4, #> 33.9, 21.5, 15.5, 15.2, 13.3, 19.2, 27.3, 26, 30.4, 15.8, 19.7, #> 15, 21.4), cyl = c(6, 6, 4, 6, 8, 6, 8, 4, 4, 6, 6, 8, 8, 8, #> 8, 8, 8, 4, 4, 4, 4, 8, 8, 8, 8, 4, 4, 4, 8, 6, 8, 4), disp = c(160, #> 160, 108, 258, 360, 225, 360, 146.7, 140.8, 167.6, 167.6, 275.8, #> 275.8, 275.8, 472, 460, 440, 78.7, 75.7, 71.1, 120.1, 318, 304, #> 350, 400, 79, 120.3, 95.1, 351, 145, 301, 121), hp = c(110, 110, #> 93, 110, 175, 105, 245, 62, 95, 123, 123, 180, 180, 180, 205, #> 215, 230, 66, 52, 65, 97, 150, 150, 245, 175, 66, 91, 113, 264, #> 175, 335, 109), drat = c(3.9, 3.9, 3.85, 3.08, 3.15, 2.76, 3.21, #> 3.69, 3.92, 3.92, 3.92, 3.07, 3.07, 3.07, 2.93, 3, 3.23, 4.08, #> 4.93, 4.22, 3.7, 2.76, 3.15, 3.73, 3.08, 4.08, 4.43, 3.77, 4.22, #> 3.62, 3.54, 4.11), wt = c(2.62, 2.875, 2.32, 3.215, 3.44, 3.46, #> 3.57, 3.19, 3.15, 3.44, 3.44, 4.07, 3.73, 3.78, 5.25, 5.424, #> 5.345, 2.2, 1.615, 1.835, 2.465, 3.52, 3.435, 3.84, 3.845, 1.935, #> 2.14, 1.513, 3.17, 2.77, 3.57, 2.78), qsec = c(16.46, 17.02, #> 18.61, 19.44, 17.02, 20.22, 15.84, 20, 22.9, 18.3, 18.9, 17.4, #> 17.6, 18, 17.98, 17.82, 17.42, 19.47, 18.52, 19.9, 20.01, 16.87, #> 17.3, 15.41, 17.05, 18.9, 16.7, 16.9, 14.5, 15.5, 14.6, 18.6), #> vs = c(0, 0, 1, 1, 0, 1, 0, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, #> 1, 1, 1, 1, 0, 0, 0, 0, 1, 0, 1, 0, 0, 0, 1), am = c(1, 1, #> 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 0, #> 0, 0, 0, 0, 1, 1, 1, 1, 1, 1, 1), gear = c(4, 4, 4, 3, 3, #> 3, 3, 4, 4, 4, 4, 3, 3, 3, 3, 3, 3, 4, 4, 4, 3, 3, 3, 3, #> 3, 4, 5, 5, 5, 5, 5, 4), carb = c(4, 4, 1, 1, 2, 1, 4, 2, #> 2, 4, 4, 3, 3, 3, 4, 4, 4, 1, 2, 1, 1, 2, 2, 4, 2, 1, 2, #> 2, 4, 6, 8, 2))
do.call(fn, list(mtcars))
#> [[1]] #> pkgdown::build_site() #> #> [[2]] #> build_reference(pkg, lazy = FALSE, examples = examples, run_dont_run = run_dont_run, #> mathjax = mathjax, seed = seed, path = file.path(path, "reference"), #> depth = 1L, preview = FALSE) #> #> [[3]] #> purrr::map(topics, build_reference_topic, path, pkg = pkg, lazy = lazy, #> depth = depth, examples = examples, run_dont_run = run_dont_run, #> mathjax = mathjax) #> #> [[4]] #> .f(.x[[i]], ...) #> #> [[5]] #> data_reference_topic(topic, pkg, path = path, examples = examples, #> run_dont_run = run_dont_run, mathjax = mathjax, depth = depth) #> #> [[6]] #> as_data(tags$tag_examples[[1]], env = new.env(parent = globalenv()), #> topic = tools::file_path_sans_ext(topic$file_in), path = path, #> examples = examples, run_dont_run = run_dont_run, depth = depth) #> #> [[7]] #> as_data.tag_examples(tags$tag_examples[[1]], env = new.env(parent = globalenv()), #> topic = tools::file_path_sans_ext(topic$file_in), path = path, #> examples = examples, run_dont_run = run_dont_run, depth = depth) #> #> [[8]] #> purrr::pmap_chr(list(code = code, run = run, show = show), format_example_chunk, #> env = child_env(env), path = path, topic = topic, obj_id = id_generator$id) #> #> [[9]] #> .f(code = .l[[c(1L, 1L)]], run = .l[[c(2L, 1L)]], show = .l[[c(3L, #> 1L)]], ...) #> #> [[10]] #> evaluate::evaluate(code, env, new_device = TRUE) #> #> [[11]] #> evaluate_call(expr, parsed$src[[i]], envir = envir, enclos = enclos, #> debug = debug, last = i == length(out), use_try = stop_on_error != #> 2L, keep_warning = keep_warning, keep_message = keep_message, #> output_handler = output_handler, include_timing = include_timing) #> #> [[12]] #> timing_fn(handle(ev <- withCallingHandlers(withVisible(eval(expr, #> envir, enclos)), warning = wHandler, error = eHandler, message = mHandler))) #> #> [[13]] #> handle(ev <- withCallingHandlers(withVisible(eval(expr, envir, #> enclos)), warning = wHandler, error = eHandler, message = mHandler)) #> #> [[14]] #> try(f, silent = TRUE) #> #> [[15]] #> tryCatch(expr, error = function(e) { #> call <- conditionCall(e) #> if (!is.null(call)) { #> if (identical(call[[1L]], quote(doTryCatch))) #> call <- sys.call(-4L) #> dcall <- deparse(call)[1L] #> prefix <- paste("Error in", dcall, ": ") #> LONG <- 75L #> msg <- conditionMessage(e) #> sm <- strsplit(msg, "\n")[[1L]] #> w <- 14L + nchar(dcall, type = "w") + nchar(sm[1L], type = "w") #> if (is.na(w)) #> w <- 14L + nchar(dcall, type = "b") + nchar(sm[1L], #> type = "b") #> if (w > LONG) #> prefix <- paste0(prefix, "\n ") #> } #> else prefix <- "Error : " #> msg <- paste0(prefix, conditionMessage(e), "\n") #> .Internal(seterrmessage(msg[1L])) #> if (!silent && identical(getOption("show.error.messages"), #> TRUE)) { #> cat(msg, file = outFile) #> .Internal(printDeferredWarnings()) #> } #> invisible(structure(msg, class = "try-error", condition = e)) #> }) #> #> [[16]] #> tryCatchList(expr, classes, parentenv, handlers) #> #> [[17]] #> tryCatchOne(expr, names, parentenv, handlers[[1L]]) #> #> [[18]] #> doTryCatch(return(expr), name, parentenv, handler) #> #> [[19]] #> withCallingHandlers(withVisible(eval(expr, envir, enclos)), warning = wHandler, #> error = eHandler, message = mHandler) #> #> [[20]] #> withVisible(eval(expr, envir, enclos)) #> #> [[21]] #> eval(expr, envir, enclos) #> #> [[22]] #> eval(expr, envir, enclos) #> #> [[23]] #> do.call(fn, list(mtcars)) #> #> [[24]] #> (function (...) #> sys.calls())(list(mpg = c(21, 21, 22.8, 21.4, 18.7, 18.1, 14.3, #> 24.4, 22.8, 19.2, 17.8, 16.4, 17.3, 15.2, 10.4, 10.4, 14.7, 32.4, #> 30.4, 33.9, 21.5, 15.5, 15.2, 13.3, 19.2, 27.3, 26, 30.4, 15.8, #> 19.7, 15, 21.4), cyl = c(6, 6, 4, 6, 8, 6, 8, 4, 4, 6, 6, 8, #> 8, 8, 8, 8, 8, 4, 4, 4, 4, 8, 8, 8, 8, 4, 4, 4, 8, 6, 8, 4), #> disp = c(160, 160, 108, 258, 360, 225, 360, 146.7, 140.8, #> 167.6, 167.6, 275.8, 275.8, 275.8, 472, 460, 440, 78.7, 75.7, #> 71.1, 120.1, 318, 304, 350, 400, 79, 120.3, 95.1, 351, 145, #> 301, 121), hp = c(110, 110, 93, 110, 175, 105, 245, 62, 95, #> 123, 123, 180, 180, 180, 205, 215, 230, 66, 52, 65, 97, 150, #> 150, 245, 175, 66, 91, 113, 264, 175, 335, 109), drat = c(3.9, #> 3.9, 3.85, 3.08, 3.15, 2.76, 3.21, 3.69, 3.92, 3.92, 3.92, #> 3.07, 3.07, 3.07, 2.93, 3, 3.23, 4.08, 4.93, 4.22, 3.7, 2.76, #> 3.15, 3.73, 3.08, 4.08, 4.43, 3.77, 4.22, 3.62, 3.54, 4.11 #> ), wt = c(2.62, 2.875, 2.32, 3.215, 3.44, 3.46, 3.57, 3.19, #> 3.15, 3.44, 3.44, 4.07, 3.73, 3.78, 5.25, 5.424, 5.345, 2.2, #> 1.615, 1.835, 2.465, 3.52, 3.435, 3.84, 3.845, 1.935, 2.14, #> 1.513, 3.17, 2.77, 3.57, 2.78), qsec = c(16.46, 17.02, 18.61, #> 19.44, 17.02, 20.22, 15.84, 20, 22.9, 18.3, 18.9, 17.4, 17.6, #> 18, 17.98, 17.82, 17.42, 19.47, 18.52, 19.9, 20.01, 16.87, #> 17.3, 15.41, 17.05, 18.9, 16.7, 16.9, 14.5, 15.5, 14.6, 18.6 #> ), vs = c(0, 0, 1, 1, 0, 1, 0, 1, 1, 1, 1, 0, 0, 0, 0, 0, #> 0, 1, 1, 1, 1, 0, 0, 0, 0, 1, 0, 1, 0, 0, 0, 1), am = c(1, #> 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, #> 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1, 1), gear = c(4, 4, 4, 3, #> 3, 3, 3, 4, 4, 4, 4, 3, 3, 3, 3, 3, 3, 4, 4, 4, 3, 3, 3, #> 3, 3, 4, 5, 5, 5, 5, 5, 4), carb = c(4, 4, 1, 1, 2, 1, 4, #> 2, 2, 4, 4, 3, 3, 3, 4, 4, 4, 1, 2, 1, 1, 2, 2, 4, 2, 1, #> 2, 2, 4, 6, 8, 2))) #>
# Specify the function name either by supplying a string # identifying the function (it should be visible in .env): invoke("call_inspect", letters)
#> call_inspect(`1`, `2`, `3`, `4`, `5`, `6`, `7`, `8`, `9`, `10`, #> `11`, `12`, `13`, `14`, `15`, `16`, `17`, `18`, `19`, `20`, #> `21`, `22`, `23`, `24`, `25`, `26`)
# Or by changing the .bury argument, with which you can also change # the argument prefix: invoke(call_inspect, mtcars, .bury = c("inspect!", "col"))
#> `inspect!`(mpg = col1, cyl = col2, disp = col3, hp = col4, drat = col5, #> wt = col6, qsec = col7, vs = col8, am = col9, gear = col10, #> carb = col11)