14 Comments

I've used it from time to time (both inside and outside of tidyverse contexts, recently via `rlang::inject()`), and I always feel like I probably *should* be using `do.call()`. If I'm using rlang for something else, are there performance considerations?

I found it easier to remember what !!! did once I started thinking of it as visually tying the input to ... (... with connectors coming off the top, basically). `!!!x` is roughly "dot-dot-dot-ize x" in my head now.

Expand full comment

I like the "dot-dot-dot-ize x" helper, now I can hopefully remember going forward :)

Expand full comment

I've only used !!! in conjunction with syms() inside a function that uses tidy evaluation (i.e dplyr)

eg. f <- function(data, group_cols) { data %>% group_by(!!!syms(group_cols)) %>% ... }

where x is a character vector of 1 or more elements

I didn't know of any other uses until now. Very interesting.

Expand full comment

I often use !!! In shiny, particularly when user have the option to select single or multiple inputs. Quite useful and simple.

Expand full comment

Thanks Hadley, great post! Now that your company name change has many of us trying to learn python (*ducks*) I'd be really curious for your thoughts on how this compares to the use of the 'unpacking operators' * & ** ? I have no idea how the mechanics compare, but I feel like I have struggled more with !!! than with python's unpacking operators. (maybe only because Duncan had already gotten .dots and do.call() patterns into my head for R?).

Expand full comment

Yes, the Python approach seems simpler and more universal

Expand full comment

Instead of do.call(), I prefer purrr::reduce or base::Reduce. Their names seem to indicate more specifically what I'm trying to accomplish. That being said, the implementations are different because Reduce and friends will call the function multiple times.

Expand full comment

I learned about this this week, while working in a shiny app. I have to create a few tab panels and i wanted to do it with functional programming. `tabsetPanel(!!!lapply(c("a", "b"), \(x) tabPanel(x)))`.

Expand full comment

Thank you for this very interesting post! I used !!! several times in packages where I wanted to control a list of variables which should give the right subset and the right order of the final output (an excel file). An external list of variables enters a function of the package and I can filter and reorder the the default list of variables according to it thanks to !!! in the function.

Expand full comment

I use do.call in functions that are mostly wrappers to other functions (from ggplot2, survminer, etc). This makes it ‘easier’ for analysts to change a few arguments or change arguments that are lists for full inner-function when parameterization a standard pipeline that my team delivers for supporting our department.

I use !!! when dynamically creating UI in shiny apps when the list can have varying elements. But I use do.call when I need to also pass arguments.

Expand full comment

*that are lists that are passed to inner-functions

Expand full comment
Aug 16, 2023·edited Aug 16, 2023

I use it for shiny applications in combination with pmap and modules, for example multiple ui elements:

tabsetPanel(

!!!pmap(control_tibble,

module_x_ui

)

Expand full comment

Great summary and context on !!! I have found !!! useful mostly when creating my own functions around various dplyr functions and piped analysis.

Expand full comment
Aug 11, 2023·edited Aug 11, 2023

I have used !!! a few times. Like you said, it does feel like magic to me, and in practice I don't find myself using it often. I have been curious about tidy evaluation for some time, but since my job (as an analyst) does not involve writing "software-level" code, I rarely run into a situation where I really need to learn and use tidy evaluation. I think this is a reason why it still feels like magic to me.

Expand full comment