Understanding [<-, [[<-, and vec_c for vctrs list_of

133 views Asked by At

Asking question that I asked on the RStudio community forums in case anyone is able to provide assistance here.

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).

0

There are 0 answers