% Generated by roxygen2: do not edit by hand
% Please edit documentation in R/nse-inject.R
\name{splice-operator}
\alias{splice-operator}
\alias{!!!}
\title{Splice operator \verb{!!!}}
\description{
The splice operator \verb{!!!} implemented in \link[=dyn-dots]{dynamic dots}
injects a list of arguments into a function call. It belongs to the
family of \link[=topic-inject]{injection} operators and provides the same
functionality as \code{\link[=do.call]{do.call()}}.

The two main cases for splice injection are:
\itemize{
\item Turning a list of inputs into distinct arguments. This is
especially useful with functions that take data in \code{...}, such as
\code{\link[base:cbind]{base::rbind()}}.

\if{html}{\out{<div class="sourceCode r">}}\preformatted{dfs <- list(mtcars, mtcars)
inject(rbind(!!!dfs))
}\if{html}{\out{</div>}}
\item Injecting \link[=topic-defuse]{defused expressions} like
\link[=sym]{symbolised} column names.

For tidyverse APIs, this second case is no longer as useful
since dplyr 1.0 and the \code{across()} operator.
}
}
\section{Where does \verb{!!!} work?}{


\verb{!!!} does not work everywhere, you can only use it within certain
special functions:
\itemize{
\item Functions taking \link[=dyn-dots]{dynamic dots} like \code{\link[=list2]{list2()}}.
\item Functions taking \link[=topic-defuse]{defused} and
\link[=topic-data-mask]{data-masked} arguments, which are dynamic by
default.
\item Inside \code{\link[=inject]{inject()}}.
}

Most tidyverse functions support \verb{!!!} out of the box. With base
functions you need to use \code{\link[=inject]{inject()}} to enable \verb{!!!}.

Using the operator out of context may lead to incorrect results,
see \ifelse{html}{\link[=topic-inject-out-of-context]{What happens if I use injection operators out of context?}}{\link[=topic-inject-out-of-context]{What happens if I use injection operators out of context?}}.
}

\section{Splicing a list of arguments}{


Take a function like \code{\link[base:cbind]{base::rbind()}} that takes data in \code{...}. This
sort of functions takes a variable number of arguments.

\if{html}{\out{<div class="sourceCode r">}}\preformatted{df1 <- data.frame(x = 1)
df2 <- data.frame(x = 2)

rbind(df1, df2)
#>   x
#> 1 1
#> 2 2
}\if{html}{\out{</div>}}

Passing individual arguments is only possible for a fixed amount of
arguments. When the arguments are in a list whose length is
variable (and potentially very large), we need a programmatic
approach like the splicing syntax \verb{!!!}:

\if{html}{\out{<div class="sourceCode r">}}\preformatted{dfs <- list(df1, df2)

inject(rbind(!!!dfs))
#>   x
#> 1 1
#> 2 2
}\if{html}{\out{</div>}}

Because \code{rbind()} is a base function we used \code{\link[=inject]{inject()}} to
explicitly enable \verb{!!!}. However, many functions implement \link[=list2]{dynamic dots} with \verb{!!!} implicitly enabled out of the box.

\if{html}{\out{<div class="sourceCode r">}}\preformatted{tidyr::expand_grid(x = 1:2, y = c("a", "b"))
#> # A tibble: 4 x 2
#>       x y    
#>   <int> <chr>
#> 1     1 a    
#> 2     1 b    
#> 3     2 a    
#> 4     2 b

xs <- list(x = 1:2, y = c("a", "b"))
tidyr::expand_grid(!!!xs)
#> # A tibble: 4 x 2
#>       x y    
#>   <int> <chr>
#> 1     1 a    
#> 2     1 b    
#> 3     2 a    
#> 4     2 b
}\if{html}{\out{</div>}}

Note how the expanded grid has the right column names. That's
because we spliced a \emph{named} list. Splicing causes each name of the
list to become an argument name.

\if{html}{\out{<div class="sourceCode r">}}\preformatted{tidyr::expand_grid(!!!set_names(xs, toupper))
#> # A tibble: 4 x 2
#>       X Y    
#>   <int> <chr>
#> 1     1 a    
#> 2     1 b    
#> 3     2 a    
#> 4     2 b
}\if{html}{\out{</div>}}
}

\section{Splicing a list of expressions}{


Another usage for \verb{!!!} is to inject \link[=topic-defuse]{defused expressions} into \link[=topic-data-mask]{data-masked}
dots. However this usage is no longer a common pattern for
programming with tidyverse functions and we recommend using other
patterns if possible.

First, instead of using the \link[=topic-data-mask-programming]{defuse-and-inject pattern} with \code{...}, you can simply pass
them on as you normally would. These two expressions are completely
equivalent:

\if{html}{\out{<div class="sourceCode r">}}\preformatted{my_group_by <- function(.data, ...) \{
  .data \%>\% dplyr::group_by(!!!enquos(...))
\}

# This equivalent syntax is preferred
my_group_by <- function(.data, ...) \{
  .data \%>\% dplyr::group_by(...)
\}
}\if{html}{\out{</div>}}

Second, more complex applications such as \link[=topic-metaprogramming]{transformation patterns} can be solved with the \code{across()}
operation introduced in dplyr 1.0. Say you want to take the
\code{mean()} of all expressions in \code{...}. Before \code{across()}, you had to
defuse the \code{...} expressions, wrap them in a call to \code{mean()}, and
inject them in \code{summarise()}.

\if{html}{\out{<div class="sourceCode r">}}\preformatted{my_mean <- function(.data, ...) \{
  # Defuse dots and auto-name them
  exprs <- enquos(..., .named = TRUE)

  # Wrap the expressions in a call to `mean()`
  exprs <- purrr::map(exprs, ~ call("mean", .x, na.rm = TRUE))

  # Inject them
  .data \%>\% dplyr::summarise(!!!exprs)
\}
}\if{html}{\out{</div>}}

It is much easier to use \code{across()} instead:

\if{html}{\out{<div class="sourceCode r">}}\preformatted{my_mean <- function(.data, ...) \{
  .data \%>\% dplyr::summarise(across(c(...), ~ mean(.x, na.rm = TRUE)))
\}
}\if{html}{\out{</div>}}
}

\section{Performance of injected dots and dynamic dots}{


Take this \link[=dyn-dots]{dynamic dots} function:

\if{html}{\out{<div class="sourceCode r">}}\preformatted{n_args <- function(...) \{
  length(list2(...))
\}
}\if{html}{\out{</div>}}

Because it takes dynamic dots you can splice with \verb{!!!} out of the
box.

\if{html}{\out{<div class="sourceCode r">}}\preformatted{n_args(1, 2)
#> [1] 2

n_args(!!!mtcars)
#> [1] 11
}\if{html}{\out{</div>}}

Equivalently you could enable \verb{!!!} explicitly with \code{\link[=inject]{inject()}}.

\if{html}{\out{<div class="sourceCode r">}}\preformatted{inject(n_args(!!!mtcars))
#> [1] 11
}\if{html}{\out{</div>}}

While the result is the same, what is going on under the hood is
completely different. \code{\link[=list2]{list2()}} is a dots collector that
special-cases \verb{!!!} arguments. On the other hand, \code{\link[=inject]{inject()}}
operates on the language and creates a function call containing as
many arguments as there are elements in the spliced list. If you
supply a list of size 1e6, \code{inject()} is creating one million
arguments before evaluation. This can be much slower.

\if{html}{\out{<div class="sourceCode r">}}\preformatted{xs <- rep(list(1), 1e6)

system.time(
  n_args(!!!xs)
)
#>    user  system elapsed
#>   0.009   0.000   0.009

system.time(
  inject(n_args(!!!xs))
)
#>    user  system elapsed
#>   0.445   0.012   0.457
}\if{html}{\out{</div>}}

The same issue occurs when functions taking dynamic dots are called
inside a data-masking function like \code{dplyr::mutate()}. The
mechanism that enables \verb{!!!} injection in these arguments is the
same as in \code{inject()}.
}

\seealso{
\itemize{
\item \ifelse{html}{\link[=topic-inject]{Injecting with !!, !!!, and glue syntax}}{\link[=topic-inject]{Injecting with !!, !!!, and glue syntax}}
\item \code{\link[=inject]{inject()}}
\item \code{\link[=exec]{exec()}}
}
}
