Skip to content

Issues with handlers attribute #136

Closed
@lionel-

Description

@lionel-

Using defer() in the execution env causes a self-reference that may cause undefined behaviour (may just need a documentation note to recommend deferring expressions in private environments):

local({
  withr::defer(NULL)
  print(environment())
})
#> *infloop*

local_ functions cause side effects in arbitrary environments:

local(envir = asNamespace("rlang"), {
  withr::local_options(list())
})

names(attributes(asNamespace("rlang")))
#> [1] "handlers"

Deferring expressions in a non-top-level global frame causes the message about deferred events to be printed, even though the on-exit expressions are correctly unwound.

options(foo = FALSE)

local(envir = globalenv(), {
  withr::local_options(list(foo = TRUE))
})
#> Setting deferred event(s) on global environment.
#>   * Execute (and clear) with `deferred_run()`.
#>   * Clear (without executing) with `deferred_clear()`.

getOption("foo")
#> [1] FALSE

The handler attributes lingers around despite the handler having been called:

attr(globalenv(), "handler")
#> [[1]]
#> [[1]]$expr
#> reset_options(old)
#>
#> [[1]]$envir
#> <environment: 0x7fc2d2fa98c0>

I would expect no message in this case and the handler attribute to be cleaned up after execution. A non-top-level global frame can be detected with:

is_global_frame <- sys.parents() == 0

# TRUE if top-level
sum(is_global_frame) == 1

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