| name | rlang-patterns |
| description | rlang metaprogramming patterns for data-masking, injection operators, and dynamic dots. Use when mentions "tidy evaluation", "avaliação tidy", "rlang", "metaprogramming", "metaprogramação", "metaprogramação em R", "data-masking", "data masking", "mascaramento de dados", "embrace", "embrace operator", "operador embrace", "{{}}", "enquo", "!!", "!!!", "injection", "injeção", "inject", "injetar", "dynamic dots", "...", "NSE", "non-standard evaluation", "avaliação não padrão", "avaliação não-padrão", "quo", "quos", "sym", "syms", "data_sym", "data_syms", ".data", ".env", "pronouns", "pronomes", "defuse", "defusing", "write functions with tidy eval", "escrever funções com tidy eval", "funções com tidy eval", "usar enquo", "use enquo", "usar embrace", "use embrace", "usar !!", "use !!", "usar !!!", "use !!!", "forward arguments", "encaminhar argumentos", or writing functions that use tidy evaluation in R. |
| version | 1.1.0 |
| user-invocable | false |
| allowed-tools | Read, Grep, Glob |
Modern rlang Patterns for Data-Masking
Metaprogramming framework that powers tidyverse data-masking
Core Concepts
Data-masking allows R expressions to refer to data frame columns as if they were variables in the environment. rlang provides the metaprogramming framework that powers tidyverse data-masking.
Key rlang Tools
- Embracing
{{}} - Forward function arguments to data-masking functions
- Injection
!! - Inject single expressions or values
- Splicing
!!! - Inject multiple arguments from a list
- Dynamic dots - Programmable
... with injection support
- Pronouns
.data/.env - Explicit disambiguation between data and environment variables
Function Argument Patterns
Forwarding with {{}}
Use {{}} to forward function arguments to data-masking functions:
my_summarise <- function(data, var) {
data |> dplyr::summarise(mean = mean({{ var }}))
}
mtcars |> my_summarise(cyl)
mtcars |> my_summarise(cyl * am)
mtcars |> my_summarise(.data$cyl)
Forwarding ... (No Special Syntax Needed)
my_group_by <- function(.data, ...) {
.data |> dplyr::group_by(...)
}
my_select <- function(.data, ...) {
.data |> dplyr::select(...)
}
my_pivot_longer <- function(.data, ...) {
.data |> tidyr::pivot_longer(c(...))
}
Names Patterns with .data
Use .data pronoun for programmatic column access:
my_mean <- function(data, var) {
data |> dplyr::summarise(mean = mean(.data[[var]]))
}
mtcars |> my_mean("cyl")
my_select_vars <- function(data, vars) {
data |> dplyr::select(all_of(vars))
}
mtcars |> my_select_vars(c("cyl", "am"))
Injection Operators
When to Use Each Operator
| Operator | Use Case | Example |
|---|
{{ }} | Forward function arguments | summarise(mean = mean({{ var }})) |
!! | Inject single expression/value | summarise(mean = mean(!!sym(var))) |
!!! | Inject multiple arguments | group_by(!!!syms(vars)) |
.data[[]] | Access columns by name | mean(.data[[var]]) |
Advanced Injection with !!
var <- "cyl"
mtcars |> dplyr::summarise(mean = mean(!!sym(var)))
df <- data.frame(x = 1:3)
x <- 100
df |> dplyr::mutate(scaled = x / !!x)
mtcars |> dplyr::summarise(mean = mean(!!data_sym(var)))
Splicing with !!!
vars <- c("cyl", "am")
mtcars |> dplyr::group_by(!!!syms(vars))
mtcars |> dplyr::group_by(!!!data_syms(vars))
args <- list(na.rm = TRUE, trim = 0.1)
mtcars |> dplyr::summarise(mean = mean(cyl, !!!args))
Dynamic Dots Patterns
Using list2() for Dynamic Dots Support
my_function <- function(...) {
dots <- list2(...)
}
my_function(a = 1, b = 2)
my_function(!!!list(a = 1, b = 2))
my_function("{name}" := value)
my_function(a = 1, )
Name Injection with Glue Syntax
name <- "result"
list2("{name}" := 1)
my_mean <- function(data, var) {
data |> dplyr::summarise("mean_{{ var }}" := mean({{ var }}))
}
mtcars |> my_mean(cyl)
mtcars |> my_mean(cyl * am)
my_mean <- function(data, var, name = englue("mean_{{ var }}")) {
data |> dplyr::summarise("{name}" := mean({{ var }}))
}
mtcars |> my_mean(cyl, name = "cylinder_mean")
Pronouns for Disambiguation
.data and .env Best Practices
cyl <- 1000
mtcars |> dplyr::summarise(
data_cyl = mean(.data$cyl),
env_cyl = mean(.env$cyl),
ambiguous = mean(cyl)
)
vars <- c("cyl", "am")
for (var in vars) {
result <- mtcars |> dplyr::summarise(mean = mean(.data[[var]]))
print(result)
}
Programming Patterns
Bridge Patterns
Converting between data-masking and tidy selection behaviors:
my_group_by <- function(data, vars) {
data |> dplyr::group_by(across({{ vars }}))
}
mtcars |> my_group_by(starts_with("c"))
my_group_by <- function(data, vars) {
data |> dplyr::group_by(across(all_of(vars)))
}
mtcars |> my_group_by(c("cyl", "am"))
Transformation Patterns
my_mean <- function(data, var) {
data |> dplyr::summarise(mean = mean({{ var }}, na.rm = TRUE))
}
my_means <- function(data, ...) {
data |> dplyr::summarise(across(c(...), ~ mean(.x, na.rm = TRUE)))
}
my_means_manual <- function(.data, ...) {
vars <- enquos(..., .named = TRUE)
vars <- purrr::map(vars, ~ expr(mean(!!.x, na.rm = TRUE)))
.data |> dplyr::summarise(!!!vars)
}
Error-Prone Patterns to Avoid
Don't Use These Deprecated/Dangerous Patterns
var <- "cyl"
code <- paste("mean(", var, ")")
eval(parse(text = code))
!!sym(var)
with(mtcars, mean(get(var)))
with(mtcars, mean(!!sym(var)))
mtcars |> summarise(mean(.data[[var]]))
Common Mistakes
my_func <- function(x) {
x <- force(x)
quo(mean({{ x }}))
}
my_func <- function(data, var) data |> summarise(mean = mean({{ var }}))
my_func <- function(data, var) {
var <- enquo(var)
data |> summarise(mean = mean(!!var))
}
Package Development with rlang
Import Strategy
Imports: rlang
importFrom(rlang, enquo, enquos, expr, !!!, :=)
Documentation Tags
Testing rlang Functions
test_that("function supports data masking", {
result <- my_function(mtcars, cyl)
expect_equal(names(result), "mean_cyl")
result2 <- my_function(mtcars, cyl * 2)
expect_true("mean_cyl * 2" %in% names(result2))
})
test_that("function supports injection", {
var <- "cyl"
result <- my_function(mtcars, !!sym(var))
expect_true(nrow(result) > 0)
})
This modern rlang approach enables clean, safe metaprogramming while maintaining the intuitive data-masking experience users expect from tidyverse functions.