Hello everyone, I am trying to better understand the behavior of [<-
, [[<-
, vec_c
, and c
for list_of classes. I am defining a list_of
subclass that essentially is a list of a character vectors that should be split on spaces. I want to use the assignment operators to adjust values within as necessary, but am struggling to fully understand the vctrs
implementation. I have provided a reprex below that highlights what I'm trying to figure out.
Example class
library(vctrs)
library(stringr)
new_example <- function(x = list()) {
if (vec_is(x, character())) {
x <- str_split(x, " ")
}
new_list_of(x,
ptype = character(),
class = "example")
}
vec_ptype_full.example <- function(x, ...) {
"example"
}
vec_ptype_abbr.example <- function(x, ...) {
"xmpl"
}
Boiler plate for coercion and casting
vec_ptype2.example <- function(x, y, ...) UseMethod("vec_ptype2.example", y)
vec_ptype2.example.default <- function(x, y, ..., x_arg = "x", y_arg = "y") {
vec_default_ptype2(x, y, x_arg = x_arg, y_arg = y_arg)
}
vec_cast.example <- function(x, to, ...) UseMethod("vec_cast.example")
vec_cast.example.default <- function(x, to, ...) vec_default_cast(x, to)
Coercion between example and character
vec_ptype2.example.character <- function(x, y, ...) x
vec_ptype2.character.example <- function(x, y, ...) y
Casting between example and character
vec_cast.character.example <- function(x, to, ...) map_chr(x, str_c, collapse = " ")
vec_cast.example.character <- function(x, to, ...) new_example(x)
vec_cast.example.example <- function(x, to, ...) new_example(x)
Testing
a <- new_example("a b")
a
#> <example[1]>
#> [[1]]
#> [1] "a" "b"
# Error
a[2] <- "c d"
#> Error: Can't cast `x` <list_of<character>> to `to` <example>.
# String not split
a[[2]] <- "e f"
a
#> <example[2]>
#> [[1]]
#> [1] "a" "b"
#>
#> [[2]]
#> [1] "e f"
# String is split
a[[2]] <- c("e", "f")
a
#> <example[2]>
#> [[1]]
#> [1] "a" "b"
#>
#> [[2]]
#> [1] "e" "f"
# String is split
vec_c(a, "g h")
#> <example[3]>
#> [[1]]
#> [1] "a" "b"
#>
#> [[2]]
#> [1] "e" "f"
#>
#> [[3]]
#> [1] "g" "h"
c(a, "g h")
#> <example[3]>
#> [[1]]
#> [1] "a" "b"
#>
#> [[2]]
#> [1] "e" "f"
#>
#> [[3]]
#> [1] "g" "h"
In order to assign values to existing rows, is there a way to use either [<-
or [[<-
to assign a full string such as "d e"
and be split, or is the best option to use [[<-
with a character vector that is already split such as c("d", "e")
?
The crux of the question is, using vec_c
and c
, the new value seems to be passed through new_example
, and thus the string is split. [[<-
seems to avoid this, and [<-
converts the string to a list_of
class before sending to the constructor function, but I'm still hazy on how I could adjust these details to work in this use case (and just better understand how vctrs
is supposed to work).