Search code examples
rnon-standard-evaluation

Function not using conditional ensym() as expected


I am trying to create a function that conditionally uses an argument, which when used, is a column of a df.

Here is an example function:

 new_fx <- function(data, x, y, z=NULL){
  x <- ensym(x)
  y <- ensym(y)
  if ( !is.null(z)){
  z <- ensym(z)
  }
  print(head(data[[x]]))
  print(head(data[[y]]))
  if (!is.null(z)){
  print(z)
  }
 }

When z is left NULL, I would like the function to ignore z. However, when any column is passed as z, I would like it to be converted to a symbol by z<- ensym(z).

This is what happens when I try to use the function above:

new_fx(data=iris, x=Species, y=Petal.Width)

# [1] setosa setosa setosa setosa setosa setosa
# Levels: setosa versicolor virginica
# [1] 0.2 0.2 0.2 0.2 0.2 0.4

Everything looks good when z is left NULL. But when any other argument is passed:

new_fx(data=iris, x=Species, y=Petal.Width, z=Petal.Length)

# Error in new_fx(data = iris, x = Species, y = Petal.Width, z = Petal.Length) : 
#  object 'Petal.Length' not found

For some reason, the function has issues when the ensym() call is used inside a conditional statement.

Any suggestions?


Solution

  • when you check is.null(), you're evaluating the argument. Use missing() instead

    library(rlang)
    
     new_fx <- function(data, x, y, z){
      x <- ensym(x)
      y <- ensym(y)
      if ( !missing(z)){
      z <- ensym(z)
      }
      print(head(data[[x]]))
      print(head(data[[y]]))
      if (!missing(z)){
      print(z)
      }
     }
    
     data(iris)
    new_fx(data=iris, x=Species, y=Petal.Width)
    #> [1] setosa setosa setosa setosa setosa setosa
    #> Levels: setosa versicolor virginica
    #> [1] 0.2 0.2 0.2 0.2 0.2 0.4
    new_fx(data=iris, x=Species, y=Petal.Width, z=Petal.Length)
    #> [1] setosa setosa setosa setosa setosa setosa
    #> Levels: setosa versicolor virginica
    #> [1] 0.2 0.2 0.2 0.2 0.2 0.4
    #> Petal.Length