rtidyevalnse

NSE in nested function calls


I'd like to use a utility function to check whether a given column exists within a given data.frame. I'm piping within the tidyverse. The best I've come up with so far is

library(magrittr)

columnExists <- function(data, col) {
  tryCatch({
    rlang::as_label(rlang::enquo(col)) %in% names(data)
    },
    error=function(e) FALSE
  )
}

This works in the global environment

> mtcars %>% columnExists(mpg)
[1] TRUE
> mtcars %>% columnExists(bad)
[1] FALSE

But not when called from within another function, which is my actual use case

outerFunction <- function(d, col) {
  d %>% columnExists((col))
}
> mtcars %>% outerFunction(mpg)  # Expected TRUE
[1] FALSE
> mtcars %>% outerFunction(bad) # Expected FALSE
[1] FALSE

What am I doing wrong? Is it possible to have a single function that works correctly in the global environment and also when nested in another function?

I have found several SO posts related to checking for the existence of a given column or columns, but they all seem to assume either that the column name will be passed as a string or the call to check existence is not nested (or both). That is not the case here.


Solution

  • You want to pass though the original symbol in your outerFunction. Use

    outerFunction <- function(d, col) {
      d %>% columnExists( {{col}} )
    }
    

    The "embrace" syntax will prevent early evaluation.