1

If I make this example

match_caller <- function(x) 1L
crazy_function <- function(x) substitute(match_caller(x),list(x=x))
crazy_function2 <- function(x) substitute(match_caller(x))

a <- 10L
crazy_function(a^2)
#> match_caller(100)
crazy_function2(a^2)
#> match_caller(a^2)

It seems to show that, by using substitute with a list instead of an env, the advantage is that it evals the variables before the replacement. Is that always the case ? For now, I use force for safety reasons if I want the evaluation before the substitution, but is this useless ?

Thanks

Arnaud Feldmann
  • 761
  • 5
  • 17
  • 1
    I'd say that you don't need `force`. As you can see from the examples in `?substitute` that's exactly how you are supposed to use `substitute`. Also, for the record, you would get exactly the same result if `match_caller <- fuction(x) 1`. so the wrapping function makes no difference. – Edo Nov 19 '20 at 09:38
  • @Edo Hi, yeah, thanks for the remark. I put match call because I want to do that for catching evaluated calls. But I'll put your notice for my simple example. I don't think the `?substitute` is clear as for whether or not it evaluates the list arg. – Arnaud Feldmann Nov 19 '20 at 09:44

1 Answers1

1

I think there are already some good answers about the substitute function/lazy evaluation, and how to use substitute. I just want to quote the substitute function reference (dating back to the days of the S language):

Arguments

expr: any syntactically valid R expression
env: an environment or a list object. Defaults to the current evaluation environment.

So, yes, you can use a list but that's not what does the force.

It's the way you call it as shown in this answer which shows again how to substitute on an expression in a value [1]:

substituteExpr <- function(expr, env) {
  do.call(substitute, list(expr=expr[[1]], env=env))
}
substituteExpr(a^2, list(x=2)) # 100

If expr's value is an expression, substitutes in any variables (it's value, not the expression) bound in env.

Reference Details:

Substitution takes place by examining each component of the parse tree as follows: If it is not a bound symbol in env, it is unchanged. If it is a promise object, i.e., a formal argument to a function or explicitly created using delayedAssign(), the expression slot of the promise replaces the symbol. If it is an ordinary variable, its value is substituted, unless env is .GlobalEnv in which case the symbol is left unchanged.

Both quote and substitute are ‘special’ primitive functions which do not evaluate their arguments.

Value The mode of the result is generally "call" but may in principle be any type. In particular, single-variable expressions have mode "name" and constants have the appropriate base mode.

Note substitute works on a purely lexical basis. There is no guarantee that the resulting expression makes any sense.

Substituting and quoting often cause confusion when the argument is expression(...). The result is a call to the expression constructor function and needs to be evaluated with eval to give the actual expression object.

wp78de
  • 18,207
  • 7
  • 43
  • 71
  • Thanks for your reply. My question wasn't about how to use substitute but about the list called in the env arg. I want to know if it's systematically evaluated and I can't find the answer in the post you show. Sorry if was a bit unclear. – Arnaud Feldmann Nov 21 '20 at 06:38