# No data masking
mean(mtcars$cyl + mtcars$am)
#> [1] 6.59375
# With data masking
with(mtcars, mean(cyl + am))
#> [1] 6.59375
Day 17: rlang’s {{ }}
Wrap function arguments containing data-frame variables in rlang’s embracing operator ({{
) for simpler tidy eval of “data-masked” arguments in functions.
Introduced in rlang 0.4.0, the {{
(read as curly curly, or the embracing operator) can be used to write functions that call other data-masking functions. What’s data masking? Well, according to the rlang docs1:
1 More specifically, the topic page What is data-masking and why do I need {{
?
Data-masking is a distinctive feature of R whereby programming is performed directly on a data set, with columns defined as normal objects (Henry and Wickham 2022).
Data-masking makes it easier to program interactively with data frames by letting you pass column names as normal objects.
Here’s an example using base R’s with()
function, which allows you to evaluate an expression in a data environment:
The functions tidyverse packages like ggplot2 and dplyr use data-masking to allow you to pass bare (unquoted) column names from the data frame as arguments. Though, as mentioned, this makes life easier for interactive programming, it means that writing functions that use data-masking functions requires special interpolation of variables (a pattern of quote-and-unquoting2).
So, what does this look like? When writing a function around a tidyverse pipeline, you embrace your data-frame variables in {{ }}
. Let’s say I want to write a function that calculates the mean by a group using dplyr’s group_by()
and summarise()
functions. I’ll need to interpolate the variables in those functions, since they are inside of the data mask.
library(tidyverse)
<- function(data, var, by) {
mean_by |>
data group_by({{ by }}) |>
summarise(the_mean = mean({{ var }}, na.rm = TRUE))
}
|>
mtcars mean_by(mpg, carb)
# A tibble: 6 × 2
carb the_mean
<dbl> <dbl>
1 1 25.3
2 2 22.4
3 3 16.3
4 4 15.8
5 6 19.7
6 8 15
Learn more
For more details on {{
, data-masking, and how they work, see What is data-masking and why do I need {{
?.
For even more on data-masking and non-standard-evaluation patterns you can use with rlang’s tidy evaluation framework, check out Data mask programming patterns (and go even further with the other guides found in the Tidy-evaluation dropdown section of the rlang docs).
Want to use glue-like {
and {{
operators for names (as opposed to function arguments). Well, that’s not what the bare embracing operator is for. However, you can still learn how to do that in Name injection with "{"
and "{{"
.