Skip to content

Issues with handlers attribute #136

@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
    No fields configured for issues without a type.

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions