NEWS


cppally 1.0.0 (2026-07-02)

First major release. cppally's public API is now considered stable. While there may be structural changes to the r_df and r_raw classes in the future, cppally's vector and scalar classes are considered stable.

Breaking changes

For example, in the below pseudo-code, when x is r_null of type r_sexp, r_sexp_visit will disambiguate it as r_vec<r_sexp>(r_null), preserving its data as R's NULL but assigning its type as r_vec<r_sexp> (list).

 r_sexp_visit(x, [&]<RVector T>(const T& vec) -> bool {
  return vec.is_null();
 });

This preservation behaviour is not new, in fact all r_vec<T> vectors preserve r_null by design, allowing for efficient and easier attribute manipulation with vectors that may or may not be r_null. What is new is that previously r_null was not a visitable r_sexp object and now it is.

Data frames

std::vector

Any coercion between std::vector and cppally::r_vec is possible so long as the element coercions are supported by cppally::as

Regular sequences

Named vector hash lookups

For named vectors, lookup by name has been dramatically improved in C++ by introducing a hashing approach. It works in the following way: the first time a lookup is requested, a linear scan is done to find the named value. The second time triggers the hash map of name-value pairs to be built and cached with the vector. That second lookup is completed using the cached hash map and all subsequent lookups also use the hash map. The rationale for hashing on second lookup is covered in the 'Automatic Names Hashing' vignette.

A similar hashing approach is also used for r_factors, making conversions of strings to and from factor codes fast and analytically viable.

Copy-on-modify

cppally now supports copy-on-modify as an opt-in feature. This feature prevents accidentally overwriting data between shared objects, just like R. To opt-in, run cppally::use_copy_on_modify or set the copy_on_modify to TRUE in cpp_source.

The major downside of this feature is significantly slower element setting as every set must verify the object is not referenced by another object. This check is single-threaded and thus nearly all parallel cppally code is disabled as a safety precaution. If using copy-on-modify, it is recommended to avoid writing cppally registered R functions that rely on in-place modification.

pmap

Inspired by purrr::pmap and base::mapply, cppally::pmap is a C++ variadic function that supports applying custom C++ lambda functions across corresponding elements of multiple vectors.

With pmap it is trivial to calculate parallel statistics like max, min, etc. Example of C++ version of base::pmax applied to two vectors.

template <RVector T, RVector U>
requires requires(typename T::data_type a, typename U::data_type b) { max(a, b); }
[[cppally::register]]
auto cpp_pmax2(T x, U y){
  return pmap([](auto a, auto b){ return max(a, b); }, x, y);
}

reduce

A left-fold reduction functional that successively applies a binary function along the elements of the vector (from left-to-right).

Example: maximum value across vector of doubles

[[cppally::register]]
r_dbl cpp_max(r_vec<r_dbl> x){
  return x.reduce([](auto acc, auto curr){ return max(acc, curr); });
}

Other changes

Bug fixes

cppally 0.1.0 (2026-04-28)