The hardware and bandwidth for this mirror is donated by dogado GmbH, the Webhosting and Full Service-Cloud Provider. Check out our Wordpress Tutorial.
If you wish to report a bug, or if you are interested in having us mirror your free-software or open-source project, please feel free to contact us at mirror[@]dogado.de.

deparse_call

TODO: reorganize, put failing alternatives on top, then really wrong stuff, then inaccuracies then readability.

constructive::deparse_call() converts calls (language objects) to code. It is an alternative to base::deparse() or rlang::expr_deparse() with a slightly different scope, and 3 main differences:

x <- call('+', c(1, 2))
base::deparse(x)
#> [1] "+c(1, 2)"
rlang::expr_deparse(x)
#> [1] "+<dbl: 1, 2>"
constructive::deparse_call(x)
#> Error in `constructive::deparse_call()`:
#> ! `call` must only be made of symbols and syntactic literals
#> Caused by error in `deparse_call_impl()`:
#> ! Found element of type 'double' and length '2':
#> c(1, 2)

# this is different
y <- quote(+c(1, 2))
x[[2]]
#> [1] 1 2
y[[2]]
#> c(1, 2)
x <- quote(`*`(a + b, c))
base::deparse(x)
#> [1] "(a + b) * c"
rlang::expr_deparse(x)
#> [1] "(a + b) * c"
constructive::deparse_call(x)
#> `*`(a + b, c)

y <- quote((a + b) * c)
base::deparse(y)
#> [1] "(a + b) * c"
rlang::expr_deparse(y)
#> [1] "(a + b) * c"
constructive::deparse_call(y)
#> (a + b) * c

# x and y are different, parentheses are code!
x[[2]]
#> a + b
y[[2]]
#> (a + b)
x <- call("[")
base::deparse(x)
#> [1] "NULL[]"
rlang::expr_deparse(x)
#> [1] "NULL[]"
constructive::deparse_call(x)
#> `[`()

deparse_call() is more accurate

We present more differences below, where at least one of the alternatives is not deparsing faithfully.

deparse_call() deparse() expr_deparse()
call('+', c(1, 2)) cannot be obtained by parsing code ERROR +c(1, 2) +<dbl: 1, 2>
Infix :: and ::: can only be called on symbols `::`(1, 2) 1::2 1::2
Infix $ and @ can only have a symbol rhs `$`("a", 1) `$`("a", 1) "a"$1
Infix $ and @ create different calls when rhs is symbol or string a$"b" a$b a$"b"
Binary ops cannot be used as prefixes `*`(1) *1 `*`(1)
Binary ops cannot be used infix with > 2 args `*`(1, 2, 3) `*`(1, 2, 3) 1 * 2
Binary ops cannot be used infix with empty args `*`(1, ) 1 * 1 *
Parentheses need function call notation if 0 arg `(`() (NULL) (NULL)
Parentheses need function call notation if > 1 arg `(`(1, 2) (1) (1)
Calling = is different from passing an arg list(`=`(x, 1)) list((x = 1)) list(x = 1)
Precedence must be respected, but adding extra parentheses to respect precedence is not accurate `-`(1 + 2) -(1 + 2) -1 + 2
`+`(repeat { }, 1) (repeat {
}) + 1
repeat { } + 1
`<-`(x <- 1, 2) (x <- 1) <- 2 (x <- 1) <- 2
`*`(a + b, c) (a + b) * c (a + b) * c
`+`(x, y)(z) (x + y)(z) `+`(x, y)(z)
`^`(1^2, 4) (1^2)^4 (1^2)^4
`+`(1, 2 + 3) 1 + (2 + 3) 1 + (2 + 3)
Brackets calling no arg is different from subsetting NULL `[`() NULL[] NULL[]
Empty bracket syntax means doesn’t mean no 2nd arg, it means 2nd arg is empty symbol, so for 1 arg we need function notation `[`(x) x[] x[]
Brackets with an empty first arg need function call notation `[`(, ) [] []
Brackets taking a call to a lower precedence op as a first arg need function call notation `[`(a + b, 1) (a + b)[1] a + b[1]
Invalid function definitions can be valid code `function`(1, 2) ERROR SEGFAULT
`function`(1(2), 3) function(1, 2) 3 ERROR
Curly braces need function call notation if they have empty args `{`(1, ) {
1

}
{
1

}
Control flow constructs need function call notation if they’re used as callers `if`(TRUE, { })(1) (if (TRUE) {
})(1)
`if`(TRUE, { })(1)
Symbols with non syntactic names need backquotes `*a*` *a* `*a*`
This includes emojis `\xf0\x9f\x90\xb6` 🐶 `🐶`

deparse_call() is clearer

In the following base::deparse() and rlang::expr_deparse() are not wrong, but constructive::deparse_call() is clearer.

constructive::deparse_call() base::deparse() rlang::expr_deparse()
Simple quotes make strings that use double quotes more readable '"oh" "hey" "there"' "\"oh\" \"hey\" \"there\"" "\"oh\" \"hey\" \"there\""
Raw strings make more complex strings more readable r"["oh"\'hey'\"there"]" "\"oh\"\\'hey'\\\"there\"" "\"oh\"\\'hey'\\\"there\""
Homoglyphs are dangerous, we can use the \U{XX} notation "\U{410} \U{A0} A" "А   A" "А   A"
For symbols we need the \xXX notation c(`\xd0\x90`, "\U{A0}" = 1) c(А, ` ` = 1) c(А, ` ` = 1)
Emojis depend on font so are ambiguous "\U{1F436}" "🐶" "🐶"

deparse_call() fails rather than making things up

x <- call("(", -1)
base::deparse(x)
#> [1] "(-1)"
rlang::expr_deparse(x)
#> [1] "(-1)"
constructive::deparse_call(x)
#> Error in `constructive::deparse_call()`:
#> ! `call` must only be made of symbols and syntactic literals
#> Caused by error in `deparse_call_impl()`:
#> ! Found element of type 'double' and length '1':
#> -1

# this is different! `-` is code!
y <- quote((-1))
base::deparse(y)
#> [1] "(-1)"
rlang::expr_deparse(y)
#> [1] "(-1)"
constructive::deparse_call(y)
#> (-1)


x <- call("fun", quote(expr = ))
base::deparse(x)
#> [1] "fun()"
rlang::expr_deparse(x)
#> [1] "fun()"
constructive::deparse_call(x) # this is wrong!
#> Error in `constructive::deparse_call()`:
#> ! `call` must only be made of symbols and syntactic literals
#> Caused by error in `deparse_call_impl()`:
#> ! Found empty symbol used as sole argument of a function:
#> as.call(list(quote(fun), quote(expr = )))

# no agument and 1 missing argument is not the same!
y <- call("fun")
base::deparse(y)
#> [1] "fun()"
rlang::expr_deparse(y)
#> [1] "fun()"
constructive::deparse_call(y)
#> fun()

x <- call("!", quote(expr = ))
base::deparse(x)
#> [1] "!"
rlang::expr_deparse(x)
#> [1] "!"
constructive::deparse_call(x)
#> Error in `constructive::deparse_call()`:
#> ! `call` must only be made of symbols and syntactic literals
#> Caused by error in `deparse_call_impl()`:
#> ! Found empty symbol used as sole argument of a function:
#> as.call(list(quote(`!`), quote(expr = )))

These binaries (installable software) and packages are in development.
They may not be fully stable and should be used with caution. We make no claims about them.
Health stats visible at Monitor.