The assignment pipe (%<>%) is not found when installing only the tidyverse

According to the magrittr tidyverse page “The easiest way to get magrittr is to install the whole tidyverse”, but the assignment pipe (%<>%) is not found when installing only the tidyverse (1.2.1).

y = 10

library(tidyverse)
y %<>% log()
#> Error in y %<>% log(): could not find function "%<>%"
y
#> [1] 10

library(magrittr)
#> 
#> Attaching package: 'magrittr'
#> The following object is masked from 'package:purrr':
#> 
#>     set_names
#> The following object is masked from 'package:tidyr':
#> 
#>     extract
y %<>% log()
y
#> [1] 2.302585

Have you gone through this page?

Run library(tidyverse) to load the core tidyverse and make it available in your current R session.

The tidyverse also includes many other packages with more specialised usage. They are not loaded automatically with library(tidyverse) , so you’ll need to load each one with its own call to library().

The packages in core tidyverse are also listed in that page.

This statement (“The easiest way to get magrittr is to install the whole tidyverse”) is misleading and non-consistent with other information from tidyverse.org.

It is not misleading if you are aware of the difference between "installing" and "loading" a package in R (they are not the same).

1 Like

That’s true.

On the other hand, what is the explanation that the assignment pipe (%<>%) is working in some instances without loading the magrittr packages (just the tidyverse)? For example:

library(tidyverse)

exp(log10(100)) + 1 
#> [1] 8.389056

test_funct <- function(x){
  
  print(x)
  
  x %<>% 
    log10() %>% 
    exp()
  y = x + 1
}

print(test_funct(100))
#> [1] 100
#> [1] 8.389056

I'm not getting your point, tidyverse simply doesn't load magrittr (and the documentation doesn't says that it does), beacuse library(tidyverse) only loads the core tidyverse packages, what is the confusing part?

Please check the previous two examples and concentrate on that part when only the tidyverse is loaded.

In first example the %<>% pipe was not working. But in case of second example (test_funct()) the %<>% pipe is working.
What is the reason for the different behavior?

Here is the code:

library(tidyverse)

# 1 case, assignment pipe is not working

y = 10

y %<>% log()
#> Error in y %<>% log(): could not find function "%<>%"

print(y)
#> [1] 10

# 2 case, assignment pipe is  working

exp(log10(100)) + 1 
#> [1] 8.389056

test_funct <- function(x){
  
  print(x)
  
  x %<>% 
    log10() %>% 
    exp()
  y = x + 1
}

print(test_funct(100))
#> [1] 100
#> [1] 8.389056

You are right, %<>% is found when used in a pipe flow with %>%, even if magrittr is not directly loaded.

library(tidyverse)

y = 10

y %<>% log10() %>% exp()

y
#> [1] 2.718282

Created on 2019-06-23 by the reprex package (v0.3.0.9000)

I am really not sure why. I would assume that when used in a pipe flow with %>%, the %<>% operator is parsed by %>% operator and understand how to deal with it.

When %<>% is used on its own, it requires to have magrittr loaded after a library(magrittr) because tidyverse :package: are not reexporting %<>%

This inconsistent behavior of the pipe operators is contradicting the principle behind the tibbles (and in general the tidyverse): “The whole point of tidy data is to store variables in a consistent way…"

I think, you are right. Let's take a look at AST:

library(lobstr)
ast(y %<>% log10() %>% exp())
#> █─`%>%` 
#> ├─█─`%<>%` 
#> │ ├─y 
#> │ └─█─log10 
#> └─█─exp

Created on 2019-06-28 by the reprex package (v0.3.0)

The way I understand this, when %<>% is called, magrittr namespace is found because %>% is present.

Without %>% AST looks like this:

library(lobstr)
ast(v1 %<>% log10)
#> █─`%<>%` 
#> ├─v1 
#> └─log10

Created on 2019-06-28 by the reprex package (v0.3.0)

And namespace is not loaded most likely.

Just in case, using two non-exported functions from magrittr fails as well, so I would put my money on the fact that pipe is re-exported:

library(lobstr)
ast(v1 %<>% log10 %T>% print)
#> █─`%T>%` 
#> ├─█─`%<>%` 
#> │ ├─v1 
#> │ └─log10 
#> └─print
v1 %<>% log10 %T>% print
#> Error in v1 %<>% log10 %T>% print: could not find function "%T>%"

Created on 2019-06-28 by the reprex package (v0.3.0)

EDIT: Actually, this example is more illuminating, I think:

library(tidyverse)
v1 %>% log10 %T>% print
#> Error in v1 %>% log10 %T>% print: could not find function "%T>%"

library(lobstr)
ast(v1 %>% log10 %T>% print)
#> █─`%T>%` 
#> ├─█─`%>%` 
#> │ ├─v1 
#> │ └─log10 
#> └─print

Created on 2019-06-28 by the reprex package (v0.3.0)

This version fails because when %T>% is called there is no magrittr namespace to look at.

3 Likes

Only ˋ%>%ˋ is reexported. You need to load package magrittr for other operators.

I'm sure that I'm messing things more complicated inside my brain by staying awake so late, but can you or someone else please explain why is this happening?

With pipes, I thought the functions are supposed to be evaluated from left to right. Probably I can even find some online references, if you insist. So, by this argument, %T>% should have been evaluated after %>%, and hence it should have access to magrittr namespace.

But that's not what is happening here, and hence my reasoning must be wrong. Can you please point out to me where? Or, is it the case that I'm completely wrong with this left-to-right notion?

They are evaluated from left to right. That is why pipe is evaluated first, and tee-pipe after that. At the point when tee-pipe is evaluated, there is no magrittr namespace anymore on a search path and it fails. When pipe is evaluated second, tee pipe (or any other pipe from magrittr) are enclosed in pipe and therefore magrittr namespace is on the search path.

What we can learn from that is re-exported functions do not load namespace into memory or rather it persists only until pipe is evaluated and then goes away.

1 Like