15 Comments
User's avatar
Jon Harmon's avatar

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.

Christoph Scheuch's avatar

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

Matt Brown's avatar

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.

Ringyao Jajo's avatar

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

Carl Boettiger's avatar

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?).

Hany Nagaty's avatar

Yes, the Python approach seems simpler and more universal

Kieran's avatar

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.

David Hugh-Jones's avatar

1. I think one problem with !!! is that it will only work if the function is designed to accept it. So you need to look that up, and even if the tidyverse is 100% consistent, it still produces a gap between it and the rest of R which may confuse users. I’m also not sure if I can use it within another function within an argument e.g. inject(foo(!!! bar))? Perhaps a case for adoption by base R….

2. Regarding intuitiveness, a take from Demolition Man https://medium.com/@davidhughjones/non-standard-evaluation-a-comment-9fd7a00d82b4

Johan Rosa's avatar

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)))`.

Layal's avatar

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.

Nick Giangreco's avatar

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.

Nick Giangreco's avatar

*that are lists that are passed to inner-functions

Edwin Schut's avatar

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

tabsetPanel(

!!!pmap(control_tibble,

module_x_ui

)

Wizards Points's avatar

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

zenggyu's avatar

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.