r-lib / rlang

Low-level API for programming with R
https://rlang.r-lib.org
Other
489 stars 132 forks source link

`env_inherits()` returns `TRUE` if `env` and `ancestor` are identical #1723

Open lhdjung opened 4 days ago

lhdjung commented 4 days ago

This appears even if no binding was created. If it's correct behavior, I haven't found information about this property of R environments anywhere – it's not shown by env_parents(), for instance.

library(rlang)

e1 <- env(a = 1, b = 2, c = 3)
e2 <- env(d = 4, e = 5, f = 6)
e3 <- env()

env_inherits(e1, e1)
#> [1] TRUE
env_inherits(e2, e2)
#> [1] TRUE
env_inherits(e3, e3)
#> [1] TRUE

Created on 2024-06-30 with reprex v2.1.0

Session info ``` r sessioninfo::session_info() #> ─ Session info ─────────────────────────────────────────────────────────────── #> setting value #> version R version 4.4.0 (2024-04-24) #> os macOS Ventura 13.4.1 #> system x86_64, darwin20 #> ui X11 #> language (EN) #> collate en_US.UTF-8 #> ctype en_US.UTF-8 #> tz Europe/Berlin #> date 2024-06-30 #> pandoc 3.1.11 @ /Applications/RStudio.app/Contents/Resources/app/quarto/bin/tools/x86_64/ (via rmarkdown) #> #> ─ Packages ─────────────────────────────────────────────────────────────────── #> package * version date (UTC) lib source #> cli 3.6.2 2023-12-11 [1] CRAN (R 4.4.0) #> digest 0.6.35 2024-03-11 [1] CRAN (R 4.4.0) #> evaluate 0.23 2023-11-01 [1] CRAN (R 4.4.0) #> fastmap 1.1.1 2023-02-24 [1] CRAN (R 4.4.0) #> fs 1.6.4 2024-04-25 [1] CRAN (R 4.4.0) #> glue 1.7.0 2024-01-09 [1] CRAN (R 4.4.0) #> htmltools 0.5.8.1 2024-04-04 [1] CRAN (R 4.4.0) #> knitr 1.46 2024-04-06 [1] CRAN (R 4.4.0) #> lifecycle 1.0.4 2023-11-07 [1] CRAN (R 4.4.0) #> magrittr 2.0.3 2022-03-30 [1] CRAN (R 4.4.0) #> purrr 1.0.2 2023-08-10 [1] CRAN (R 4.4.0) #> R.cache 0.16.0 2022-07-21 [1] CRAN (R 4.4.0) #> R.methodsS3 1.8.2 2022-06-13 [1] CRAN (R 4.4.0) #> R.oo 1.26.0 2024-01-24 [1] CRAN (R 4.4.0) #> R.utils 2.12.3 2023-11-18 [1] CRAN (R 4.4.0) #> reprex 2.1.0 2024-01-11 [1] CRAN (R 4.4.0) #> rlang 1.1.4 2024-06-04 [1] CRAN (R 4.4.0) #> rmarkdown 2.26 2024-03-05 [1] CRAN (R 4.4.0) #> rstudioapi 0.16.0 2024-03-24 [1] CRAN (R 4.4.0) #> sessioninfo 1.2.2 2021-12-06 [1] CRAN (R 4.4.0) #> styler 1.10.3 2024-04-07 [1] CRAN (R 4.4.0) #> vctrs 0.6.5 2023-12-01 [1] CRAN (R 4.4.0) #> withr 3.0.0 2024-01-16 [1] CRAN (R 4.4.0) #> xfun 0.43 2024-03-25 [1] CRAN (R 4.4.0) #> yaml 2.3.8 2023-12-11 [1] CRAN (R 4.4.0) #> #> [1] /Library/Frameworks/R.framework/Versions/4.4-x86_64/Resources/library #> #> ────────────────────────────────────────────────────────────────────────────── ``` Created on 2024-06-30 with [reprex v2.1.0](https://reprex.tidyverse.org)
lhdjung commented 3 days ago

For anyone who wants to test whether an environment inherits from / contains itself, this function works more intuitively (and correctly?):

library(rlang)

env_contains_itself <- function(env) {
    names_bound <- env_names(env)
    for (name in names_bound) {
        if (identical(env, env[[name]])) {
            return(TRUE)
        }
    }
    FALSE
}

e1 <- env(a = 1, b = 2, c = 3)
e2 <- env(d = 4, e = 5, f = 6)
e3 <- env()

env_contains_itself(e1)
#> [1] FALSE
env_contains_itself(e2)
#> [1] FALSE
env_contains_itself(e3)
#> [1] FALSE

# Does return `TRUE` if the environment has
# a binding to itself:
e2$f <- e2
env_contains_itself(e2)
#> [1] TRUE

# To be sure, both functions say the *empty*
# environment doesn't contain itself:
e4 <- empty_env()

env_inherits(e4, e4)
#> [1] FALSE
env_contains_itself(e4)
#> [1] FALSE

Created on 2024-07-01 with reprex v2.1.0

lionel- commented 2 days ago

It's a tough design question. Does this predicate answers a structural question (ancestor part of the ancestry) or a semantic question (is the ancestor in scope)?