vctrs provides a framework for working with vector classes in a generic way. However, it implements several compatibility fallbacks to base R methods. In this reference you will find how vctrs tries to be compatible with your vector class, and what base methods you need to implement for compatibility.

If you’re starting from scratch, we think you’ll find it easier to start using new_vctr() as documented in vignette("s3-vector"). This guide is aimed for developers with existing vector classes.

Aggregate operations with fallbacks

All vctrs operations are based on four primitive generics described in the next section. However there are many higher level operations. The most important ones implement fallbacks to base generics for maximum compatibility with existing classes.

  • vec_slice() falls back to the base [ generic if no vec_proxy() method is implemented. This way foreign classes that do not implement vec_restore() can restore attributes based on the new subsetted contents.

  • vec_c() and vec_rbind() now fall back to base::c() if the inputs have a common parent class with a c() method (only if they have no self-to-self vec_ptype2() method).

    vctrs works hard to make your c() method success in various situations (with NULL and NA inputs, even as first input which would normally prevent dispatch to your method). The main downside compared to using vctrs primitives is that you can’t combine vectors of different classes since there is no extensible mechanism of coercion in c(), and it is less efficient in some cases.

The vctrs primitives

Most functions in vctrs are aggregate operations: they call other vctrs functions which themselves call other vctrs functions. The dependencies of a vctrs functions are listed in the Dependencies section of its documentation page. Take a look at vec_count() for an example.

These dependencies form a tree whose leaves are the four vctrs primitives. Here is the diagram for vec_count():

The coercion generics

The coercion mechanism in vctrs is based on two generics:

See the theory overview.

Two objects with the same class and the same attributes are always considered compatible by ptype2 and cast. If the attributes or classes differ, they throw an incompatible type error.

Coercion errors are the main source of incompatibility with vctrs. See the howto guide if you need to implement methods for these generics.

The proxy and restoration generics

These generics are essential for vctrs but mostly optional. vec_proxy() defaults to an identity function and you normally don’t need to implement it. The proxy a vector must be one of the atomic vector types, a list, or a data frame. By default, S3 lists that do not inherit from "list" do not have an identity proxy. In that case, you need to explicitly implement vec_proxy() or make your class inherit from list.