rdplyrrlangtidyeval

What is the difference between ensym and enquo when programming with dplyr?


Relatively new to tidy evaluation and while the functions I'm making work, I want to know why different helper functions are used. For example, what is the difference between enquo and ensym? In the function I made below to capture daily average and moving average they're interchangeable:

library(dplyr)
library(lubridate)
library(rlang)
library(zoo)

manipulate_for_ma <- function(data, group_var, da_col_name, summary_var, ma_col_name) {
  group_var <- ensym(group_var) 
  summary_var <- enquo(summary_var)
  da_col_name <- ensym(da_col_name) 
  ma_col_name <- enquo(ma_col_name)
  
  data %>% 
    group_by(!!group_var) %>%
    summarise(!!da_col_name := mean(!!summary_var, na.rm = TRUE)) %>% 
    mutate(!!ma_col_name := rollapply(!!da_col_name,
                                      30,
                                      mean,
                                      na.rm = TRUE,
                                      partial = TRUE,
                                      fill = NA)) %>% 
    rename(date = !!group_var)
}

lakers %>%
 mutate(date = ymd(date)) %>%
 manipulate_for_ma(group_var = date,
                   da_col_name = points_per_play_da,
                   summary_var = points,
                   points_per_play_ma)

# A tibble: 78 x 3
   date       points_per_play_da points_per_play_ma
   <date>                  <dbl>              <dbl>
 1 2008-10-28              0.413              0.458
 2 2008-10-29              0.431              0.459
 3 2008-11-01              0.408              0.456
 4 2008-11-05              0.386              0.457

I've read about enquo here and ensym here. Is the difference that ensym is more restrictive and only takes strings or string-like objects?


Solution

  • Another take :

    library(rlang)
    library(dplyr, warn.conflicts = FALSE)
    
    test <- function(x){
      Species <- "bar"
      cat("--- enquo builds a quosure from any expression\n")
      print(enquo(x))
      cat("--- ensym captures a symbol or a literal string as a symbol\n")
      print(ensym(x))
      cat("--- evaltidy will evaluate the quosure in its environment\n")
      print(eval_tidy(enquo(x)))
      cat("--- evaltidy will evaluate a symbol locally\n")
      print(eval_tidy(ensym(x)))
      cat("--- but both work fine where the environment doesn't matter\n")
      identical(select(iris,!!ensym(x)), select(iris,!!enquo(x)))
    }
    
    Species = "foo"
    test(Species)
    #> --- enquo builds a quosure from any expression
    #> <quosure>
    #> expr: ^Species
    #> env:  global
    #> --- ensym captures a symbol or a literal string as a symbol
    #> Species
    #> --- evaltidy will evaluate the quosure in its environment
    #> [1] "foo"
    #> --- evaltidy will evaluate a symbol locally
    #> [1] "bar"
    #> --- but both work fine where the environment doesn't matter
    #> [1] TRUE
    
    test("Species")
    #> --- enquo builds a quosure from any expression
    #> <quosure>
    #> expr: ^"Species"
    #> env:  empty
    #> --- ensym captures a symbol or a literal string as a symbol
    #> Species
    #> --- evaltidy will evaluate the quosure in its environment
    #> [1] "Species"
    #> --- evaltidy will evaluate a symbol locally
    #> [1] "bar"
    #> --- but both work fine where the environment doesn't matter
    #> [1] TRUE
    test(paste0("Spec","ies"))
    #> --- enquo builds a quosure from any expression
    #> <quosure>
    #> expr: ^paste0("Spec", "ies")
    #> env:  global
    #> --- ensym captures a symbol or a literal string as a symbol
    #> Only strings can be converted to symbols
    

    Created on 2019-09-23 by the reprex package (v0.3.0)