Search code examples
rtidyrtidyversense

Why do I need to wrap function returning a character vector into c() when passing to tidyr ... argument?


See example:

df <- data.frame(month=rep(1:3,2),
                 student=rep(c("Amy", "Bob"), each=3),
                 A=c(9, 7, 6, 8, 6, 9),
                 B=c(6, 7, 8, 5, 6, 7))
cnames<-function(){c(month="month",student="student")}

When wrapping cnames() into c() the call to tidyr::gather works:

df2 <- df %>% 
  gather(variable, value, -c(cnames()))

but it fails when i call it with cnames() or even (cnames()) only :

df2 <- df %>% 
  gather(variable, value, -(cnames()))

i.e.

> df2 <- df %>% 
+   gather(variable, value, -(cnames()))
Error in -(cnames()) : invalid argument to unary operator

I am guessing this has something to do with NSE but what exactly?


Solution

  • I believe the 'proper' way of doing it in current tidyverse/tidyselect would be...

    df %>% gather(variable, value, -(!! cnames()))
    

    The reason df %>% gather(variable, value, -c(cnames())) works is because c() is specifically handled differently than usual in tidyselect. See string coercion affects c() #37

    df %>% gather(variable, value, -(cnames())) does not work because the entire expression evalutes (including the -), so you get the same error as if you run simply -(cnames())