[R] Function in default parameter value closing over variables defined later in the enclosing function
Duncan Murdoch
murdoch@dunc@n @end|ng |rom gm@||@com
Wed Jan 23 15:56:25 CET 2019
On 23/01/2019 4:53 a.m., Ivan Krylov wrote:
> Hi!
>
> I needed to generalize a loss function being optimized inside another
> function, so I made it a function argument with a default value. It
> worked without problems, but later I noticed that the inner function,
> despite being defined in the function arguments, somehow closes over a
> variable belonging to the outer function, which is defined later.
>
> Example:
>
> outside <- function(inside = function() print(secret)) {
> secret <- 'secret'
> inside()
> }
> outside()
>
> I'm used to languages that have both lambdas and variable declaration
> (like perl5 -Mstrict or C++11), so I was a bit surprised.
Defaults of variables are evaluated in the evaluation frame of the call.
So the inside() function is created in the evaluation frame, and it's
environment will be that frame.
When it is called it will create a new evaluation frame (empty in your
example), with a parent being its environment, i.e. the evaluation frame
from when it was created, so it will be able to see your secret variable.
If it made an assignment to secret using standard "<-" assignment, it
would create a new variable in its own evaluation frame, but if it used
superassignment "<<-", it would modify the original secret variable.
>
> Does this work because R looks up the variable by name late enough at
> runtime for the `secret` variable to exist in the parent environment of
> the `inside` function? Can I rely on it? Is this considered bad style?
> Should I rewrite it (and how)?
I would consider it bad style if the inside() function had anything
other than a trivial definition as in your example. However, in my
opinion it would be fine to write it as
outside <- function(inside = defaultInsideFn) {
defaultInsideFn <- function() print(secret)
secret <- 'secret'
inside()
}
which is essentially equivalent, other than having a shorter header on
the outside() function.
Duncan Murdoch
More information about the R-help
mailing list