1  Pipe: magrittr and native

Published

June 23, 2023

Modified

January 8, 2024

1.1 Resources

1.2 Native pipe

  • The native pipe was introduced in R 4.1 alongside the use of new anonymous function syntax.
  • Pipe the left-hand side into the first argument of the right-hand side. In normal usage, it works almost exactly like the magrittr pipe.
  • In R 4.2 the native pipe got the _ syntax to insert the left-hand side into a named argument of the right-hand side function. However, this functionality is not as powerful as in %>%, see Section 1.3.

The tidyverse style guidelines are moving over to the usage of the native pipe. The native pipe is used for all examples in the Second Edition of R for Data Science. Hadley discusses the move to the native pipe in Documentation in the release notes for purrr 1.0.0. There, he notes the advantages of the greater simplicity of the native pipe and the clarity provided by anonymous functions, see Section 1.2.2.

1.2.1 Usage

The pipe operator is implemented as a syntax transformation.

quote(mtcars |> subset(cyl == 4) |> nrow())
#> nrow(subset(mtcars, cyl == 4))

Like the magrittr pipe, the native pipe places the left-hand side into the first argument of the right hand side.

mtcars |> filter(cyl == 4) |> head()
#>                 mpg cyl  disp hp drat    wt  qsec vs am gear carb
#> Datsun 710     22.8   4 108.0 93 3.85 2.320 18.61  1  1    4    1
#> Merc 240D      24.4   4 146.7 62 3.69 3.190 20.00  1  0    4    2
#> Merc 230       22.8   4 140.8 95 3.92 3.150 22.90  1  0    4    2
#> Fiat 128       32.4   4  78.7 66 4.08 2.200 19.47  1  1    4    1
#> Honda Civic    30.4   4  75.7 52 4.93 1.615 18.52  1  1    4    2
#> Toyota Corolla 33.9   4  71.1 65 4.22 1.835 19.90  1  1    4    1

There are two ways to place the left-hand side elsewhere in the right-hand side function: anonymous functions and _ placeholder

1.2.2 The pipe and the anonymous function

The pipe and the new shorthand syntax for the anonymous function both debuted with R 4.1.

mtcars |> subset(cyl == 4) |> (\(x) lm(mpg ~ disp, data = x))()
#> 
#> Call:
#> lm(formula = mpg ~ disp, data = x)
#> 
#> Coefficients:
#> (Intercept)         disp  
#>     40.8720      -0.1351

Example of using anonymous function to make code more clear taken from purrr 1.0.0 release. This is part of the move away from formula notation (~) to anonymous function.

# Previously
1:5 %>%
  map(~ rnorm(10, .x)) %>%
  map_dbl(mean)
#> [1] 0.6989054 2.1852344 2.9494400 3.3351719 4.6173895

# Use of anonymous function
1:5 |>
  map(\(x) rnorm(10, x)) |>
  map_dbl(mean) 
#> [1] 1.447187 1.826487 2.715834 3.273295 5.036881

1.2.3 Underscore placeholder

The _ placeholder is similar to magrittr . placeholder. However, the _ placeholder can only be used once and must be used with a named argument. See Section 1.3 for examples of these limitations. Nevertheless, the _ placeholder does cover most use cases.

mtcars |> subset(cyl == 4) |> lm(mpg ~ disp, data = _)
#> 
#> Call:
#> lm(formula = mpg ~ disp, data = subset(mtcars, cyl == 4))
#> 
#> Coefficients:
#> (Intercept)         disp  
#>     40.8720      -0.1351

In R 4.3 the _ placeholder can be used with extraction functions $, or as the head of a chain of extractions [, [[, or @. However, it cannot be used with [[ to start the extraction as in case 4 of the magrittr pipe below.

mtcars |> _$cyl
#>  [1] 6 6 4 6 8 6 8 4 4 6 6 8 8 8 8 8 8 4 4 4 4 8 8 8 8 4 4 4 8 6 8 4
mtcars |> subset(cyl == 4) |> lm(mpg ~ disp, data = _) |> _$coef[[2]]
#> [1] -0.1351418

1.3 The magrittr pipe

Uses of the magrittr . notation that are easier or not possible with the native pipe.

  1. Use of . in unnamed arguments
c(1:3) %>% paste("No", .)
#> [1] "No 1" "No 2" "No 3"
  1. Use of multiple . in right-hand side
c(1:3) %>% paste(., "No", .)
#> [1] "1 No 1" "2 No 2" "3 No 3"

# Need anonymous function with native pipe
c(1:3) |> (\(x) paste(x, "No", x))()
#> [1] "1 No 1" "2 No 2" "3 No 3"
  1. Use of . in nested functions
iris %>% 
  bind_rows(mutate(., Species = "all")) %>% 
  count(Species)
#>      Species   n
#> 1        all 150
#> 2     setosa  50
#> 3 versicolor  50
#> 4  virginica  50
  1. Use of . with infix operators on left- and right-hand side
mtcars %>% `[[`("cyl")
#>  [1] 6 6 4 6 8 6 8 4 4 6 6 8 8 8 8 8 8 4 4 4 4 8 8 8 8 4 4 4 8 6 8 4