tidyverse / magrittr

Improve the readability of R code with the pipe
https://magrittr.tidyverse.org
Other
957 stars 157 forks source link

Assignment pipe `%<>%` breaks if R-native `|>` pipes used in chain instead of magrittr-native pipes `%>%` #269

Closed SimonDedman closed 9 months ago

SimonDedman commented 9 months ago

As raised in a comment here, moving to a full issue for tracking purposes. Magrittr assignment pipe %<>% sends its output to the console instead of assigning it to the starting object, if one uses the base |> pipe instead of magrittr's %>% within the chain.

tmp <- mtcars
tmp %<>%
  bind_cols(example = rep(1, 32)) %>%
  summarise_all(mean)
# sends output to tmp, updating in place

tmp <- mtcars
tmp %<>%
  bind_cols(example = rep(1, 32)) |> 
  summarise_all(mean)
# sends output to console, tmp is unchanged

@lionel- reply:

The |> rewrites the input in nested form at parse time:

quote(a %<>% b() |> c())
#> c(a %<>% b())

So there is no appealing way to make it work in a %<>% pipeline.

This seems like a shame since the base pipe has a keyboard shortcut and compresses to a pretty arrow if one uses (e.g.) Fira Code font. And also if folks are starting to use base pipe more commonly, I suspect this issue might come up more frequently?

I vaguely remember a comment (by @hadley possibly?) suggesting the assign pipe isn't well loved / good practice? Can't remember why that was/is, since it feels very natural to me: within the 'new' pipe workflow concept, one of the tenets/benefits is that you no longer create many intermediary objects which clutter the environment and require manual removal.

[this is completely unrelated but in case anyone reads this: package::function() fails for magrittr::%<>%; is there a way to do this?]

lionel- commented 9 months ago

As you noted supporting |> would be hard and create ambiguities since foo |> bar() and bar(foo) are indistinguishable. So unfortunately this is out of scope for magrittr.

In general we are migrating to the base pipe even though it has fewer features. You can still use magrittr, we've made %>% much more lean and performant in the last release so it'll remain in the best shape it can be for the foreseeable future. It's in maintenance mode though, so we won't be adding new features.

since it feels very natural to me: within the 'new' pipe workflow concept, one of the tenets/benefits is that you no longer create many intermediary objects which clutter the environment and require manual removal.

With %<>% you're still creating intermediary objects for completed pipelines. It's purely a shorthand that removes a repeat of the leading object passed to the pipeline and updated at the end. This is one more syntax piece to learn for newcomers, and even if you know about it this operator makes you pause while reading code if you're not used to it. So we're recommending the more explicit syntax of foo <- foo %>% bar() or foo <- foo |> bar(). The repeat is not that awful and has the benefit of being much clearer.