-
Notifications
You must be signed in to change notification settings - Fork 58
Description
The problem: Argument names of a memoised function (say, f) can be hijacked by names in the body or enclosing environment of the memoising function (memoise(f)).
Example:
memoise(function(hash) hash)("Am I OK?")
#> [1] "9ec45ba0998d8bc3150c..." (output truncated)This is not a problem that is likely to be encountered for exotic names, like `_f`. For ordinary syntactic names, like hash or args, the likelihood of a name clash is still very low, but not zero. Nevertheless, it might be worthwhile to reduce this likelihood to zero, as this seems possible with a few small changes to memoise() (and, accordingly, has_cache()).
A solution:
- To fix clashes with names in the enclosing environment — invoke such names by explicit reference to bindings in the enclosing environment.
- To fix clashes with names assigned in the memoised function body — call the underlying (non-memoised) function
fin the calling environment, rather than in the function's execution environment, as currently done.
Implementing 1) amounts to changing `_f` to encl$`_f`, etc., where encl gets parent.env(environment()). Implementing 2) amounts to replacing .init_call in memoise.R with eval.parent(`[[<-`(match.call(), 1L, encl$`_f`)).
I have implement such fixes in commits 018ef0a, 7a46d42, e32fb1b. memoise() is even a bit simpler, now, because bquote()'ing is no longer necessary. All existing tests pass, in addition to a test that verifies the absence of name clashes.
With such changes, argument names won't be hijacked by internal names:
memoise(function(hash) hash)("OK!")
#> [1] "OK!"