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:
- Sortedness. Describes the sorted state of a vector3. Can be:
-
SORTED_DECR_NA_1ST
: -2 (sorted in decreasing order, withNA
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_
-
- No
NA
.0
if a vector might possibly containNA
values, otherwise1
.
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:
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:
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:
- The R object to wrap
- An integer indicating the sortedness (see above for the sortedness enum values)
- An integer indicating whether it contains
NA
.1
if it does, otherwise0
.
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:
alt_data2(x)
#> [1] 1 1
Remember that 1 1 means “sorted in increasing order” and “no NA values”.