Skip to content

Review vec_is_list() check on vec_proxy() #1208

@DavisVaughan

Description

@DavisVaughan

@lionel- and I discussed the concept of a list-rcrd in more detail. Essentially this is a list that has some vectorized attributes that can get sliced alongside the list. We determined that one possible implementation of this idea is (in my own words):

  • The list itself is used as the core data structure.

  • The special vectorized attributes are stored as an attribute of the list. The easiest thing to do would be to store them as a named list in a single attribute called something like vctrs:::vectorized.

  • The list explicitly inherits from "list", along with whatever extra class is used on top of that. Say its vctrs_list_rcrd.

  • The vec_proxy.vctrs_list_rcrd method should return a data frame. The first column is a list-col containing the list. The remaining columns are the vectorized attributes.

This would currently work in vctrs, except for the fact that vec_is_list() has the following check: If x inherits explicitly from "list", then vec_proxy(x) must also be a list. This should currently fail here (although I think it doesn't because of a bug).

I don't remember exactly why we have that restriction, but it seems reasonable that we might try to remove it to allow these list-rcrds to work.

One possible implementation follows, but as @lionel- mentioned to me, the important part is that this doesn't require any vctrs specific helper, and can live completely outside vctrs.

library(vctrs)

new_list_rcrd <- function(x, vectorized, ..., class = character()) {
  structure(
    x, 
    `vctrs:::vectorized` = vectorized, 
    ..., 
    class = c(class, "vctrs_list_rcrd", "list")
  )
}

vec_proxy.vctrs_list_rcrd <- function(x, ...) {
  vectorized <- attr(x, "vctrs:::vectorized")
  x <- unclass(x)
  cols <- list(`vctrs:::data` = x)
  cols <- c(cols, vectorized)
  new_data_frame(cols)
}

vec_restore.vctrs_list_rcrd <- function(x, to, ...) {
  data <- x[["vctrs:::data"]]
  x[["vctrs:::data"]] <- NULL
  new_list_rcrd(data, x)
}

x <- new_list_rcrd(
  x = list(a = 1:3, b = 2:5), 
  vectorized = list(
    special1 = c(TRUE, FALSE),
    special2 = c("x", "y")
  )
)

x
#> $a
#> [1] 1 2 3
#> 
#> $b
#> [1] 2 3 4 5
#> 
#> attr(,"vctrs:::vectorized")
#> attr(,"vctrs:::vectorized")$special1
#> [1]  TRUE FALSE
#> 
#> attr(,"vctrs:::vectorized")$special2
#> [1] "x" "y"
#> 
#> attr(,"class")
#> [1] "vctrs_list_rcrd" "list"

vec_slice(x, c(1, 1, 2))
#> $a
#> [1] 1 2 3
#> 
#> $a
#> [1] 1 2 3
#> 
#> $b
#> [1] 2 3 4 5
#> 
#> attr(,"vctrs:::vectorized")
#> attr(,"vctrs:::vectorized")$special1
#> [1]  TRUE  TRUE FALSE
#> 
#> attr(,"vctrs:::vectorized")$special2
#> [1] "x" "x" "y"
#> 
#> attr(,"class")
#> [1] "vctrs_list_rcrd" "list"

Created on 2020-08-05 by the reprex package (v0.3.0)

Metadata

Metadata

Assignees

No one assigned

    Labels

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions