vctrs icon indicating copy to clipboard operation
vctrs copied to clipboard

Assigning to OOB locations directly adjacent to a vector

Open DavisVaughan opened this issue 2 years ago • 1 comments

This is somewhat related to #1301 Discovered from looking at https://stackoverflow.com/questions/70794504/using-native-time-in-clock-package-and-having-error-with-rbind-error-levels-c

I have discovered that even with the levels.vctrs_vctr fix, we still can't call rbind() if we have a rcrd column.

library(vctrs)

x <- new_rcrd(list(a = 1L))
df <- data.frame(x = x)

rbind(df, df)
#> Error:
#> ! Can't assign to elements that don't exist.
#> x Location 2 doesn't exist.
#> ℹ There are only 1 element.

This boils down to the fact that rbind() constructs the final result by using [<- to "extend" each column, like this:

library(vctrs)

# Base R supports vector "extension" but we don't
y <- c("a", "b")

`[<-`(y, 3L, "c")
#> [1] "a" "b" "c"

try(vec_assign(y, 3L, "c"))
#> Error : Can't assign to elements that don't exist.
#> x Location 3 doesn't exist.
#> ℹ There are only 2 elements.

# Obviously base R also supports things we don't want too...
`[<-`(y, 4L, "c")
#> [1] "a" "b" NA  "c"

Since [<-.vctrs_rcrd uses vec_assign(), we end up with the above error in rbind() because of this

> vctrs:::`[<-.vctrs_rcrd`
function (x, i, value) 
{
    i <- maybe_missing(i, TRUE)
    value <- vec_cast(value, x)
    out <- vec_assign(vec_data(x), i, vec_data(value))
    vec_restore(out, x)
}

I don't think that vec_assign() should gain this ability directly (but I could be wrong), but the idea in general isn't completely crazy, since tibble seems to do it:

https://github.com/tidyverse/tibble/blob/64fefd56b12d7922a408b6b2505b8474dc1e470b/R/subsetting.R#L646

library(tibble)

df <- tibble(x = 1:2)

df[3,] <- tibble(x = 3)

df
#> # A tibble: 3 × 1
#>       x
#>   <int>
#> 1     1
#> 2     2
#> 3     3

DavisVaughan avatar Jan 28 '22 20:01 DavisVaughan

the idea in general isn't completely crazy, since tibble seems to do it:

We've added num_as_location(oob = "extend") for tibble. It might make sense to make vec_assign() more flexible too.

lionel- avatar Jan 28 '22 23:01 lionel-