Skip to contents

Experimental, more robust, and more user-friendly version of base R substitute.

Usage

substitute2(expr, env)

Arguments

expr

Unevaluated expression in which substitution has to take place.

env

List, or an environment that will be coerced to list, from which variables will be taken to inject into expr.

Details

For convenience function will turn any character elements of env argument into symbols. In case if character is of length 2 or more, it will raise an error. It will also turn any list elements into list calls instead. Behaviour can be changed by wrapping env into I call. In such case any symbols must be explicitly created, for example using as.name function. Alternatively it is possible to wrap particular elements of env into I call, then only those elements will retain their original class.

Comparing to base R substitute, substitute2 function:

  1. substitutes calls argument names as well

  2. by default converts character elements of env argument to symbols

  3. by default converts list elements of env argument to list calls

  4. does not accept missing env argument

  5. evaluates elements of env argument

Note

Conversion of character to symbol and list to list call works recursively for each list element in env list. If this behaviour is not desired for your use case, we would like to hear about that via our issue tracker. For the present moment there is an option to disable that: options(datatable.enlist=FALSE). This option is provided only for debugging and will be removed in future. Please do not write code that depends on it, but use I calls instead.

Value

Quoted expression having variables and call argument names substituted.

See also

Examples

## base R substitute vs substitute2
substitute(list(var1 = var2), list(var1 = "c1", var2 = 5L))
#> list(var1 = 5L)
substitute2(list(var1 = var2), list(var1 = "c1", var2 = 5L)) ## works also on names
#> list(c1 = 5L)

substitute(var1, list(var1 = "c1"))
#> [1] "c1"
substitute2(var1, list(var1 = I("c1"))) ## enforce character with I
#> [1] "c1"

substitute(var1, list(var1 = as.name("c1")))
#> c1
substitute2(var1, list(var1 = "c1")) ## turn character into symbol, for convenience
#> c1

## mix symbols and characters using 'I' function, both lines will yield same result
substitute2(list(var1 = var2), list(var1 = "c1", var2 = I("some_character")))
#> list(c1 = "some_character")
substitute2(list(var1 = var2), I(list(var1 = as.name("c1"), var2 = "some_character")))
#> list(c1 = "some_character")

## list elements are enlist'ed into list calls
(cl1 = substitute(f(lst), list(lst = list(1L, 2L))))
#> f(list(1L, 2L))
(cl2 = substitute2(f(lst), I(list(lst = list(1L, 2L)))))
#> f(list(1L, 2L))
(cl3 = substitute2(f(lst), list(lst = I(list(1L, 2L)))))
#> f(list(1L, 2L))
(cl4 = substitute2(f(lst), list(lst = quote(list(1L, 2L)))))
#> f(list(1L, 2L))
(cl5 = substitute2(f(lst), list(lst = list(1L, 2L))))
#> f(list(1L, 2L))
cl1[[2L]] ## base R substitute with list element
#> [[1]]
#> [1] 1
#> 
#> [[2]]
#> [1] 2
#> 
cl2[[2L]] ## same
#> [[1]]
#> [1] 1
#> 
#> [[2]]
#> [1] 2
#> 
cl3[[2L]] ## same
#> [[1]]
#> [1] 1
#> 
#> [[2]]
#> [1] 2
#> 
cl4[[2L]] ## desired
#> list(1L, 2L)
cl5[[2L]] ## automatically
#> list(1L, 2L)

## character to name and list into list calls works recursively
(cl1 = substitute2(f(lst), list(lst = list(1L, list(2L)))))
#> f(list(1L, list(2L)))
(cl2 = substitute2(f(lst), I(list(lst = list(1L, list(2L)))))) ## unless I() used
#> f(list(1L, list(2L)))
last(cl1[[2L]]) ## enlisted recursively
#> list(2L)
last(cl2[[2L]]) ## AsIs
#> [[1]]
#> [1] 2
#> 

## using substitute2 from another function
f = function(expr, env) {
  eval(substitute(
    substitute2(.expr, env),
    list(.expr = substitute(expr))
  ))
}
f(list(var1 = var2), list(var1 = "c1", var2 = 5L))
#> list(c1 = 5L)