Lock environment but not .Random.seed
Asked Answered
E

0

6

Is it possible to lock the global environment and still allow .Random.seed to be set or removed? The default behavior of lockEnvironment() is too aggressive for my use case.

lockEnvironment(globalenv())
rnorm(10)
#> Error in rnorm(10) : cannot add bindings to a locked environment
rm(.Random.seed)
#> Error in rm(.Random.seed) : 
#>   cannot remove bindings from a locked environment

Background

drake version 7.0.0 will have a new safeguard to protect reproducibility.

plan <- drake_plan(
  x = {
    data(mtcars)
    mtcars$mpg
  },
  y = mean(x)
)

plan
#> # A tibble: 2 x 2
#>   target command                            
#>   <chr>  <expr>                             
#> 1 x      {     data(mtcars)     mtcars$mpg }
#> 2 y      mean(x)

make(plan)
#> target x
#> fail x
#> Error: Target `x` failed. Call `diagnose(x)` for details. Error message:
#>   cannot add bindings to a locked environment. 
#> One of your targets tried to modify your environment,
#> which could invalidate other targets
#> and undermine reproducibility (example: 
#> https://github.com/ropensci/drake/issues/664#issuecomment-453163562).
#> Beware <<-, ->>, attach(), data(), and side effects in general.
#> Use make(lock_envir = FALSE) to avoid this error (not recommended).

The error comes from the call to data(mtcars). The very act of building x would have changed x's dependencies. Without guardrails, the workflow invalidates itself.

make(plan, lock_envir = FALSE)
#> target x
#> target y

make(plan, lock_envir = FALSE)
#> target x

But with guardrails, we run into edge cases like https://github.com/ropensci/drake/issues/749 and https://github.com/ropensci/drake/issues/675#issuecomment-458222414.

Everrs answered 21/2, 2019 at 16:17 Comment(6)
Can you pre-create it? For instance, rnorm(1); lockEnvironment(globalenv()); rnorm(10) works just fine. Realize that lockEnvironment is preventing new variables, it does not prevent changing an existing variable.Amplify
Related to a previous question (https://mcmap.net/q/684714/-how-to-unlock-environment-in-r/3358272), it would seem that this new default mode of drake::make would itself be a one-way sledge-hammer, since you cannot unlock an environment (global or otherwise) once locked. I recognize that one purpose of drake is to enforce reproducibility, so this is not an undesirable thing, but it is irreversible.Amplify
Responses: (1) Yes, drake already pre-creates the seed. It has to because of how it handles reproducible pseudo-random number generation. But we still have edge cases when user-side code tries to remove .Random.seed. (2) I deal with that as best I can in a custom unlock_environment() function.Everrs
I can't find anything that would support mostlyLockEnvironment(). (I'm a bit shocked that user code would attempt to remove that variable ... it's a dot-variable for a reason, I'd think that's a little too over-handed. Do you have a strong example showing utility in removing it?)Amplify
I am surprised too! But apparently, parallel::mclapply() and shiny both try to remove it. See here, here, and here.Everrs
Interesting! Thanks for the links. Frankly, whenever something imposes side-effect like that, I tend to get nervous/annoyed. I suppose it's for a good reason, somehow, I'll have to press the [I believe] button for now ...Amplify

© 2022 - 2024 — McMap. All rights reserved.