Question
Why do I get inconsistent error messages in R from a function that uses non-standard evaluation, and what is the best way to control this / write the function?
Initial setup that works as intended:
library(tidyverse)
df <- tibble(a = c(1,4,9),
b = c("a", "b", "c"))
> df
# A tibble: 3 × 2
a b
<dbl> <chr>
1 1 a
2 4 b
3 9 c
myFun1 <- function(df, y){
df <- df %>%
mutate(c = str_to_upper({{y}}))
return(df)
}
> myFun1(df, y = b)
# A tibble: 3 × 3
a b c
<dbl> <chr> <chr>
1 1 a A
2 4 b B
3 9 c C
Everything above works as intended. There are no errors with my function calls as shown.
Problem starts here
I made a mistake by not passing the dataframe's column as a parameter in the call, but received no error message:
> myFun1(df) # Note the missing parameter of 'y = b' on this function call.
# A tibble: 3 × 3
a b c
<dbl> <chr> <chr>
1 1 a ""
2 4 b ""
3 9 c ""
My expectation when calling a function with missing parameters is that it would throw an error, which does not happen. (Side question: Why does it return an empty string "" for column c?)
I thought I could helpfully write my own error message -- which worked -- but not in the way I intended:
myFun2 <- function(df, y){
if(is.null(y)){
stop("You are missing 'y'")
}
df <- df %>%
mutate(c = str_to_upper({{y}}))
return(df)
}
> myFun2(df)
Error in myFun2(df) : argument "y" is missing, with no default
That error above is triggered by is.null(y)
and not by my if(){stop()}
(so you ARE NOT seeing my intended error message), but what is interesting to me is that THIS IS THE ERROR MESSAGE I WAS HOPING/EXPECTING TO SEE when I called myFun1(df)
. So it seems that my use of {{y}}
in the function prevents the triggering of the error message.(?)
Note: I realize (later, with more reading) that I could get my
stop()
message to trigger if I usedif(missing(y))
, but I'm more curious about the case above, where I get the error message I was originally hoping to get without theif(){stop()}
call.
What if I try a different function, like sum()
?
I tried to change functions, as below (shown working properly first):
myFun3 <- function(data, x){
df <- data %>%
mutate(c = sum({{x}}))
return(df)
}
> myFun3(df, x = a)
# A tibble: 3 × 3
a b c
<dbl> <chr> <dbl>
1 1 a 14
2 4 b 14
3 9 c 14
...and now with same mistake as before:
> myFun3(df)
Error in `mutate()`:
ℹ In argument: `c = sum()`.
Caused by error in `sum()`:
! invalid 'type' (symbol) of argument
Run `rlang::last_trace()` to see where the error occurred.
Called from: signal_abort(cnd, .file)
Browse[1]>
So now I get an error message on the sum()
call because the wrong type -- (symbol) -- is detected, which is my {{x}}
. Okay, that makes sense (I think), but why then do I not get that same error message on the call str_to_upper({{y}})
? Isn't {{y}}
also a symbol in my original bad call of myFun1(df)
? I am trying to understand this all in the context of learning non-standard evaluation, and I am reading Advanced R, but this issue above seems pretty specific. I appreciate any insight. Thank you.