Why does `print.function` disagree with function bodies that are created with `substitute()`?

Viewed 63

In R, it is possible to do a 'macro substitution' before executing a piece of code. Using this technique, one can dynamically embed a constant into a function body before actually creating the funciton, avoiding a variable look-up:

expr = substitute(function () s, list('s'='ABCDE'))
f    = eval(expr)
f()
# [1] "ABCDE"
environment(f)
# <environment: R_GlobalEnv>

Here, the enclosing environment is R_GlobalEnv, which does not contain the variable s at all, but the function can still return "ABCDE" correctly. This seems to mean that the returned string "ABCDE" was indeed not from a variable lookup, but is embedded into the function body.

But now if you print the function, you can see that s is still there, although it is not in expr:

print(f)
# function () s
print(expr)
# function() "ABCDE"

What exactly is going on here?

1 Answers

print.function prints the srcref attribute rather than the actual source but

  1. the useSource= argument can be used to specify that the actual function source be used. It defaults to TRUE but can be specified as FALSE.
  2. body(f) will show the actual body.
  3. The srcref attribute can be removed using attr(f, "srcref") <- NULL in which case print will show the actual source. It is also possible to overwrite the srcref attribute. attr(f, "srcref") <- format(f) which works because format uses the actual source.

Here is a demonstration.

expr <- substitute(function () s, list('s'='ABCDE'))
f <- eval(expr)

f
## function () s

print(f)
## function () s

print(f, useSource = FALSE)
## function () 
## "ABCDE"

attr(f, "srcref")
## function () s

body(f)
## [1] "ABCDE"

format(f)
## [1] "function () " "\"ABCDE\""    

f <- eval(expr)
attr(f, "srcref") <- NULL
f
## function () 
## "ABCDE"

f <- eval(expr)
attr(f, "srcref") <- format(f)
f
## function () 
## "ABCDE"
Related