Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

What is the difference between sym() and parse_expr() in the rlang package?

Using the rlang package, I wonder what is the difference between sym() and parse_expr(). Consider for example the following expressions:

ex1 = sym('a')
ex2 = parse_expr('a')

They both return

a

identical(ex1, ex2)
[1] TRUE

Suppose now I need a quosure:

ex3 = quo(!!sym('a'))
ex4 = quo(!!parse_expr('a'))

In both case, the result is:

<quosure>
expr: ^a
env:  global

identical(ex3, ex4)
[1] TRUE

However, the two following are not the same for some reasons.

ex5 = quo(!!sym('a - b'))
ex6 = quo(!!parse_expr('a - b'))

Apparently they are identical as both return:

<quosure>
expr: ^a - b
env:  global

Yet,

identical(ex5, ex6)
[1] FALSE

So, my question is, what are the differences between sym() and parse_expr()? What does one do that the other cannot? And why is ex5 apparently similar to ex6, but identical(ex5, ex6) returns FALSE?

like image 594
Rtist Avatar asked Dec 14 '22 16:12

Rtist


2 Answers

Referencing my answer to this question:

A symbol is a way to refer to an R object, basically the "name" of an object. So sym is similar to as.name in base R. parse_expr on the other hand transforms some text into R expressions. This is similar to parse in base R.

Expressions can be any R code, not just code that references R objects. So you can parse the code that references an R object, but you can't turn some random code into sym if the object that the code references does not exist.

In general, you will use sym when your string refers to an object (although parse_expr would also work), and use parse_expr when you are trying to parse any other R code for further evaluation.

For your first example, a can be both a name that references an object AND an expression, so turning it into either a sym or parse_expr would practically mean the same thing. In fact, R implicitly converts the expression to a sym when it can, as shown in your first example.

For your last example however, a - b is really intended to be an expression (unless you have an R object that is weirdly named a - b). By printing the following, you will see that using sym vs parse_expr for R code that is intended to be an expression, not an R object produces two different results:

> quo(!!sym('a - b'))
<quosure: global>
~`a - b`

> quo(!!parse_expr('a-b'))
<quosure: global>
~a - b

Here, sym turns a - b into a name/symbol of an object, hence the back ticks around a - b, while parse_expr turns it into an expression as expected.

like image 193
acylam Avatar answered Dec 18 '22 00:12

acylam


To augment the previous answer, note that ex5 and ex6 are not in fact identical.

a <- 5
b <- 3
eval_tidy(ex6)
# [1] 2
eval_tidy(ex5)
# Error in eval_tidy(ex5) : object 'a - b' not found
`a - b` <- pi
eval_tidy(ex5)
# [1] 3.141593
like image 35
Weihuang Wong Avatar answered Dec 18 '22 00:12

Weihuang Wong