Skip to content

Review vec_is_list() check on vec_proxy() #1208

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

    Fields

    No fields configured for issues without a type.

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions