Customizing Vectors R
This skill covers type-stable operations and custom vector class design using the vctrs package.
Core Benefits
- •Type stability - Predictable output types regardless of input values
- •Size stability - Predictable output sizes from input sizes
- •Consistent coercion rules - Single set of rules applied everywhere
- •Robust class design - Proper S3 vector infrastructure
When to Use vctrs
Use vctrs when:
- •Building custom vector classes - Data frame compatibility, subsetting
- •Type-stable functions in packages - Guaranteed output types
- •Consistent coercion/casting - Explicit rules, predictable behavior
- •Size/length stability - Predictable sizing from inputs
Don't use vctrs when:
- •Simple one-off analyses - Base R is sufficient
- •No custom classes needed - Standard types work fine
- •Performance critical + simple operations - Base R may be faster
- •External API constraints - Must return base R types
vctrs vs Base R Decision Matrix
| Use Case | Base R | vctrs | When to Choose vctrs |
|---|---|---|---|
| Simple combining | c() | vec_c() | Need type stability, consistent rules |
| Custom classes | S3 manually | new_vctr() | Want data frame compatibility, subsetting |
| Type conversion | as.*() | vec_cast() | Need explicit, safe casting |
| Finding common type | Not available | vec_ptype_common() | Combining heterogeneous inputs |
| Size operations | length() | vec_size() | Working with non-vector objects |
Building Custom Vector Classes
See custom-vector-class.md for the complete pattern:
- •Constructor (low-level)
- •Helper (user-facing)
- •Format method
Type-Stable Functions
See type-stable-functions.md for:
- •Guaranteed output types with
vec_cast() - •Avoiding type-depends-on-data patterns
Coercion and Casting
See coercion-casting.md for:
- •Explicit casting with clear rules
- •Common type finding with
vec_ptype_common() - •Self-coercion methods
- •Cross-type coercion methods
Implementation Patterns
Coercion Methods
Define vec_ptype2.* methods for type compatibility:
vec_ptype2.pkg_percent.pkg_percent <- function(x, y, ...) new_percent() vec_ptype2.pkg_percent.double <- function(x, y, ...) double()
Casting Methods
Define vec_cast.* methods for conversion:
vec_cast.pkg_percent.double <- function(x, to, ...) new_percent(x) vec_cast.double.pkg_percent <- function(x, to, ...) vec_data(x)
See coercion-methods.md for complete examples.
Performance Considerations
When vctrs Adds Overhead
- •Simple operations -
vec_c(1, 2)vsc(1, 2) - •One-off scripts - Type safety less critical
- •Small vectors - Overhead may outweigh benefits
When vctrs Improves Performance
- •Package functions - Type stability prevents expensive re-computation
- •Complex classes - Consistent behavior reduces debugging
- •Data frame operations - Robust column type handling
- •Repeated operations - Predictable types enable optimization
Package Development
Exports and Dependencies
# DESCRIPTION Imports: vctrs # NAMESPACE - Import what you need importFrom(vctrs, vec_assert, new_vctr, vec_cast, vec_ptype_common)
Testing vctrs Classes
See testing-vctrs.md for:
- •Type stability tests
- •Coercion tests
Key Insight
vctrs is most valuable in package development where type safety, consistency, and extensibility matter more than raw speed for simple operations.
source: Sarah Johnson's gist https://gist.github.com/sj-io/3828d64d0969f2a0f05297e59e6c15ad