Search code examples
rrlangtidyeval

rlang: Error: Can't convert a function to a string


I created a function to convert a function name to string. Version 1 func_to_string1 works well, but version 2 func_to_string2 doesn't work.

func_to_string1 <- function(fun){
    print(rlang::as_string(rlang::enexpr(fun)))
}

func_to_string2 <- function(fun){
    is.function(fun)
    print(rlang::as_string(rlang::enexpr(fun)))
}

func_to_string1 works:

> func_to_string1(sum)
[1] "sum"

func_to_string2 doesn't work.

> func_to_string2(sum)
 Error: Can't convert a primitive function to a string
Call `rlang::last_error()` to see a backtrace 

My guess is that by calling the fun before converting it to a string, it gets evaluated inside function and hence throw the error message. But why does this happen since I didn't do any assignments?

My questions are why does it happen and is there a better way to convert function name to string?

Any help is appreciated, thanks!


Solution

  • This isn't a complete answer, but I don't think it fits in a comment.

    R has a mechanism called pass-by-promise, whereby a function's formal arguments are lazy objects (promises) that only get evaluated when they are used. Even if you didn't perform any assignment, the call to is.function uses the argument, so the promise is "replaced" by the result of evaluating it.

    Nevertheless, in my opinion, this seems like an inconsistency in rlang*, especially given cory's answer, which implies that R can still find the promise object even after a given parameter has been used; the mechanism to do so might not be part of R's public API though.

    *EDIT: see coments.

    Regardless, you could treat enexpr/enquo/ensym like base::missing, in the sense that you should only use them with parameters you haven't used at all in the function's body.