Skip to contents

Introduction

Note: you should have read vignette("altrepr") in order to understand this one

Wrapper objects have a (rare) description in the R source code1. Good start!

Wrapper objects are ALTREP objects designed to hold the attributes of a potentially large object and/or meta data for the object.

Metadata

Actually the metadata that’s being referred to here is not something obvious like the attributes() of an object. It’s simply a vector of integers that describe a vector in some way2. Currently these include:

  1. Sortedness. Describes the sorted state of a vector3. Can be:
    • SORTED_DECR_NA_1ST: -2 (sorted in decreasing order, with NA values sorted first)
    • SORTED_DECR: -1 (sorted in decreasing order)
    • KNOWN_UNSORTED: 0
    • SORTED_INCR: 1 (sorted in increasing order)
    • SORTED_INCR_NA_1ST: 2
    • UNKNOWN_SORTEDNESS: NA_integer_
  2. No NA. 0 if a vector might possibly contain NA values, otherwise 1.

The public API in C for this are functions such as INTEGER_NO_NA, INTEGER_IS_SORTED etc4.

Wrapper Objects in the Wild

The most likely situation you will encounter wrapper objects in normal R usage is via the sort function. Most (but not all) parameter configurations of sort will cause the function to return an ALTREP:

library(altrepr)
x <- sort(5:1)
is_altrep(x)
#> [1] TRUE

We can do our normal prying into the class metadata:

alt_classname(x)
#> [1] "wrap_integer"
alt_pkgname(x)
#> [1] "base"

Inspecting Wrapper Metadata in R

The main public interface to the sorted metadata is the is.unsorted function, which basically checks the metadata using mechanisms discussed above. This is a “true public” function in the sense that it’s a stable function provided by base R, that you can rely on in the long term:

is.unsorted(5:1)
#> [1] TRUE
5:1 |> sort() |> is.unsorted()
#> [1] FALSE

The main public interface to the NA flag is the anyNA() function:

c(1, 2, NA, 3) |> anyNA()
#> [1] TRUE
c(1, 2, 3) |> anyNA()
#> [1] FALSE

Of course altrepr provides a user-friendly utility for inspecting the metadata of known wrapper objects:

5:1 |>
  sort() |>
  wrapper_details()
#> $contents
#> [1] 1 2 3 4 5
#> 
#> $has_na
#> [1] FALSE
#> 
#> $is_sorted
#> [1] TRUE
#> 
#> $descending
#> [1] FALSE
#> 
#> $na_first
#> [1] FALSE

Creating Custom Wrapper Types

altrepr also provides a user-friendly function for creating these wrapper types, without needing sort. This lets us blatantly lie to R about our vectors!

wrapper <- wrapper_make(c(5, 3, NA, 1), is_sorted = TRUE, has_na = FALSE)
wrapper
#> [1]  5  3 NA  1
wrapper_details(wrapper)
#> $contents
#> [1]  5  3 NA  1
#> 
#> $has_na
#> [1] FALSE
#> 
#> $is_sorted
#> [1] TRUE
#> 
#> $descending
#> [1] FALSE
#> 
#> $na_first
#> [1] FALSE

This fools the public R functions as well:

is.unsorted(wrapper)
#> [1] FALSE
anyNA(wrapper)
#> [1] FALSE

There’s also an internal R function you can use (at your own risk) called wrap_meta. This isn’t documented, but it takes 3 arguments:

  1. The R object to wrap
  2. An integer indicating the sortedness (see above for the sortedness enum values)
  3. An integer indicating whether it contains NA. 1 if it does, otherwise 0.
x <- wrap_meta(10:1, 0, 0) |> .Internal()
alt_classname(x)
#> [1] "wrap_integer"
wrap_meta(10:1, 1, 0) |> 
  .Internal() |>
  is.unsorted()
#> [1] FALSE

Wrapper Data

The data for these types is quite simple. data1 contains the wrapped object, and data2 contains the metadata as an integer vector. Let’s have a look:

x <- sort(5:1)
alt_data1(x)
#> [1] 1 2 3 4 5
alt_data2(x)
#> [1] 1 1

Remember that 1 1 means “sorted in increasing order” and “no NA values”.