Reputation: 423
What does "!!" do in R, and why would you use it?
Specifically, I'm looking at a function that involves the phrase
a = !!sym("x")
where "x"
is a string. I thought sym
worked by turning a string into an object, so a = sym("x")
would set a
equal to the object x
. What is the !!
there for? I read that it unquotes whatever is after it, but I thought sym
itself unquoted strings?
I also see !!
used with other functions. What is it doing?
Upvotes: 27
Views: 19949
Reputation: 47320
When you convert a string to a symbol, it prints without the quotes, but that's NOT what unquoting means (we'll get back to that in the end).
rlang::sym()
is creating a symbol from a string, it's almost the same as base::as.symbol()
(tiny differences irrelevant to this answer), itself an alias for base::as.name()
:
nm <- "Sepal.Width"
x <- rlang::sym(nm)
x
#> Sepal.Width
typeof(x)
#> [1] "symbol"
identical(x, as.symbol(nm))
#> [1] TRUE
Those don't work, as x
and nm
are respectively a symbol and a character, so I can't multiply them by 2
:
dplyr::mutate(head(iris),SW2 = nm * 2)
#> Error in nm * 2: argument non numérique pour un opérateur binaire
dplyr::mutate(head(iris),SW2 = x * 2)
#> Error in x * 2: argument non numérique pour un opérateur binaire
!!
doesn't do anything by itself and is not a real operator, it tells mutate()
to do something though, because mutate()
is designed to recognize it.
What it tells to mutate()
is to act as if !!x
was replaced by the quoted content of x.
# equivalent to dplyr::mutate(head(iris), Sepal.Width * 2)
dplyr::mutate(head(iris), !!x * 2)
#> Sepal.Length Sepal.Width Petal.Length Petal.Width Species
#> 1 5.1 3.5 1.4 0.2 setosa
#> 2 4.9 3.0 1.4 0.2 setosa
#> 3 4.7 3.2 1.3 0.2 setosa
#> 4 4.6 3.1 1.5 0.2 setosa
#> 5 5.0 3.6 1.4 0.2 setosa
#> 6 5.4 3.9 1.7 0.4 setosa
#> Sepal.Width * 2
#> 1 7.0
#> 2 6.0
#> 3 6.4
#> 4 6.2
#> 5 7.2
#> 6 7.8
dplyr::mutate(head(iris), !!sym("Sepal.Width") * 2)
would give the same output.
Why it is called unquoting might be easier to understand by looking at this other equivalent call :
quoted <- quote(Sepal.Width * 2)
dplyr::mutate(head(iris), !!quoted)
See help("!!")
for more details.
Upvotes: 37