Skip to content

Name clashes between arguments and memoising procedure #43

@egnha

Description

@egnha

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:

  1. To fix clashes with names in the enclosing environment — invoke such names by explicit reference to bindings in the enclosing environment.
  2. To fix clashes with names assigned in the memoised function body — call the underlying (non-memoised) function f in 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!"

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions