Skip to content

Why does rlang_env_dots_list() clone? #1820

@DavisVaughan

Description

@DavisVaughan

i.e. why was a clone added here a8dea54?

Shouldn't it be up to the caller to decide whether or not to clone?

We use this in vec_c() to capture ..., and in particular with the vec_c(!!!x) case I was imagining that we could capture x without requiring any cloning of the list.

It would be nice if we could say vec_c(!!!x) was identical to list_unchop(x) with no indices.

library(vctrs)

values <- rep(list(1), 1e6)

bench::mark(
  vec_c(!!!values),
  list_unchop(values)
)
#> Warning: Some expressions had a GC in every iteration; so filtering is
#> disabled.
#> # A tibble: 2 × 6
#>   expression               min   median `itr/sec` mem_alloc `gc/sec`
#>   <bch:expr>          <bch:tm> <bch:tm>     <dbl> <bch:byt>    <dbl>
#> 1 vec_c(!!!values)       151ms    169ms      5.99    19.1MB     18.0
#> 2 list_unchop(values)    143ms    144ms      6.92    11.4MB     19.0

profmem::profmem(vec_c(!!!values), threshold = 1000)
#> Rprofmem memory profiling of:
#> vec_c(!!!values)
#> 
#> Memory allocations (>= 1000 bytes):
#> Number of 'new page' entries not displayed: 5328
#>        what    bytes      calls
#> 1     alloc  8000048    vec_c()
#> 2     alloc  4000048    vec_c()
#> 3     alloc  8000048    vec_c()
#> total       20004512

profmem::profmem(list_unchop(values), threshold = 1000)
#> Rprofmem memory profiling of:
#> list_unchop(values)
#> 
#> Memory allocations (>= 1000 bytes):
#> Number of 'new page' entries not displayed: 1391
#>        what    bytes         calls
#> 1     alloc  4000048 list_unchop()
#> 2     alloc  8000048 list_unchop()
#> total       12000096

Created on 2025-08-28 with reprex v2.1.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