7

When using dot a second time to reuse the data on the left of a pipe, passing the dot to a function . %>% f() is different to putting the dot inside the function brackets f(.). Why is this?

Debugging the %>% operator shows that . %>% identity() evaluates to a functional sequence rather than a character vector, which causes names<- to fail. I don't know how to force the evaluation of this.

# Error
c('a', 'b', 'c') %>% `names<-`(., . %>% identity())
# Works
c('a', 'b', 'c') %>% `names<-`(., identity(.))
c('a', 'b', 'c') %>% `names<-`(., . %>% identity())

Error in as.vector(x, "character") : cannot coerce type 'closure' to vector of type 'character'

c('a', 'b', 'c') %>% `names<-`(., identity(.))
# a   b   c 
#"a" "b" "c"
Ronak Shah
  • 377,200
  • 20
  • 156
  • 213
Charlie
  • 188
  • 3

1 Answers1

7

Pipe starting with . generates a function.

For example, . %>% identity is same as function(.) identity(.).

Thus,

# Error
c('a', 'b', 'c') %>% `names<-`(., . %>% identity())

is regarded as

c('a', 'b', 'c') %>% `names<-`(., function(.) identity(.))

which means the second argument of names<- is function, not a character vector.

This is documented in Using the dot-place holder as lhs.

In order to workaround, try

c('a', 'b', 'c') %>% `names<-`(., (.) %>% identity())
atusy
  • 86
  • 2
  • 1
    I would like to add that `magrittr` has a operator for setting the names, in this case use `letters[1:3] %>% magrittr::set_names({ . })` (same rule as above). – MrGumble Jul 25 '19 at 07:10
  • 2
    You are right. Though I prefer `rlang::set_names` because it uses first argument as new names if names are not specified explicitly. `letters[1:3] %>% rlang::set_names()` works without dot. – atusy Jul 25 '19 at 07:27