3

Those two functions don't give the same output, because of how works the %>% operator, but I can't understand why?

my_function <- function(x) {
 # Extract the name of x
 the_name_of_x <- deparse(substitute(x))
 print(the_name_of_x)
}

my_other_function <- function(x) {
 # Extract the name of x
 the_name_of_x <- x %>% substitute() %>% deparse()
 print(the_name_of_x)
}

# Example
my_function("zaza")
# [1] "\"zaza\""
my_other_function("zaza")
# [1] "x"

I really can't figure out why this makes a difference.

MrFlick
  • 195,160
  • 17
  • 277
  • 295
Greg Mansio
  • 109
  • 5

1 Answers1

5

You would get the same value as the first one if you used the native pipe

yet_another_function <- function(x) {
  # Extract the name of x
  the_name_of_x <- x |> substitute() |> deparse()
  print(the_name_of_x)
}

The reason is the |> pipe actually re-writes the syntax tree so it's not actually a function. Observe

quote(x |> substitute() |> deparse())
deparse(substitute(x))

However %>% is a function. It will appear on the call stack. The substitute function uses non-standard evaluation which means it looks at the expression passed to the function. The %>% function cannot re-write the call completely. It evaluates the promise of the function parameter into an expression. substitute is a special function in that if you want to capture the value a promise points to, you need to do so before the promise is evaluated.

You can see the source of the magrittr pipe function

`%>%`
function (lhs, rhs) 
{
    lhs <- substitute(lhs)
    rhs <- substitute(rhs)
    kind <- 1L
    env <- parent.frame()
    lazy <- TRUE
    .External2(magrittr_pipe)
}

And you can see how it's already using substitute to get the unevaluated expressions of it's parameters. A promise cannot survive this indirection.

MrFlick
  • 195,160
  • 17
  • 277
  • 295