maleta
maleta

Reputation: 423

What does the !! operator mean in R, particularly in the context !!sym("x")

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

Answers (1)

moodymudskipper
moodymudskipper

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

Related Questions