Release Notes
Upgrading from (0.5.1)
💥 This "upgrade guide" section collects all breaking changes we expect
users to encounter when upgrading from 0.5.1 (or 0.5.0) to 0.6.0. We will give
guidance for how to handle each.
NOTE: every breaking change has a syntax that works for both 0.5.x and
0.6.0. Use this syntax to fix up individual callsites in your codebase. After
you do, the commit that upgrades to 0.6.0 will be small and simple. See our
upgrade guide for
more details.
-
au::detail::UnitAvoidancespecializations are no longer permitted;
specializeau::UnitOrderTiebreakerinstead. (#429, #718) -
Arithmetic results that are exactly unitless (e.g., meters per meter;
seconds times hertz) will no longer produce a raw number; instead, they
produce aQuantity. The simplest fix is to wrap these in an
as_raw_number(...)call. This works for both raw numbers and dimensionless
quantities; see as_raw_number docs for more details. (#185, #705) -
coerce_asandcoerce_inare deprecated everywhere. Instead of
coerce_as(u), useas(u). If it fails to compile, read the error, and use
one ofas(u, ignore(TRUNCATION_RISK)),as(u, ignore(OVERFLOW_RISK)), or
as(u, ignore(TRUNCATION_RISK | OVERFLOW_RISK)), as appropriate. See our
conversion risk docs for more details. (#481, #710, #711, #716) -
Explicit-rep overloads (e.g.,
q.as<int>(u)instead ofq.as(u)) no longer
override safety checks. To fix new compiler errors, add a conversion risk
policy parameter, as per our conversion risk docs. (#122, #708) -
Implicit-rep overloads (e.g.,
q.as(u)) no longer necessarily return the
same rep as the input; instead, they return the "natural" output of the
underlying C++. The only existing code that should be affected is small
integer types that are subject to integer promotion. If this causes issues,
you can writeq.as<au::SameRep>(u)to request the same rep explicitly.
(#679, #685, #712, #719) -
The
Quantityconstructor now performs an implicit conversion on the
underlying value, rather than astatic_cast. This means that your compiler
warnings (say,-Wconversion) will fire in Au code in exactly the same
situations where they would have fired in the equivalent raw-numeric code. If
this surfaces new warnings, they are warnings your raw-number program would
also have produced; see our compiler warnings policy for the reasoning.
(#528, #629, #631, #633) -
Unit labels for prefixed, exponentiated units now use square brackets to
disambiguate:milli(inverse(bytes))labels asm[B^(-1)], rather than the
ambiguousmB^(-1). Brackets are omitted where they'd add nothing (so
centi(meters / seconds)is stillcm / s). If you have tests that assert
on label text for prefixed powers, they may need updating.
(#530, #605, #627)
If you find a problem upgrading from 0.5.1 to 0.6.0 that is not covered here,
please file an issue to let us
know about it!
User-facing library changes
✨ Vector and matrix support (#70, #484)
Au now supports vectors and matrices as the rep of a Quantity. You can
write meters(Eigen::Vector3d{1.0, 2.0, 3.0}) and get unit safety for the whole
vector, with all the core library operations --- arithmetic, comparison, unit
conversions --- working as you'd expect.
Getting there required rethinking some deep library foundations. The biggest is
that a conversion which doesn't name its rep now returns the type the underlying
C++ would naturally produce, rather than mechanically preserving the input rep
(#679, #685). This is essential for expression-template libraries, and it's
also simply more correct: the core design goal of a units library is "same
program, only safer", so we shouldn't force you to change the bits and bytes
flowing through your program. For the rare case where you really do want to pin
the rep, we added the SameRep tag (#712, #719).
Reasoning about "what is a scalar" also had to get more sophisticated. The new
ScalarOf<T> trait (#681) generalizes RealPart<T>: besides arithmetic types
and complex-number-like types, it understands types with a ::Scalar member
alias, which is how vector and matrix libraries advertise their element type.
That in turn lets us close a hole in our rep rules: if ScalarOf<T> is itself
quantity-like, then T is a container of quantities, so it already has units and
is not a valid rep (#666, #701).
Quantity also gained element access (#684), in both q[i] and q(i, j)
styles, each returning a Quantity of the indexed element. For writes, there's
q.mutable_view()[i], built on a new View<T> rep wrapper (#682). All the
assignment operators are ref-qualified, so the classic silent no-op
q[0] = meters(3) is now a compiler error rather than a lost write.
Also implemented in: #692.
✨ First-class Eigen support
Au works with Eigen out of the box, and ---
crucially --- without giving up any of Eigen's performance. Quantity has
full support for the lazy "expression template" types that are the source of
Eigen's speed.
Of course, preserved laziness means preserved lifetime hazards as well, so
these are now first-class topics in our documentation: every lazy operation
carries a warning admonition, and we've added a dedicated Eigen safety guide
explaining when an expression template can dangle and how eval(...) fixes it
(#713). We also refreshed the overflow and truncation discussions in light
of vector and matrix reps (#721).
Eigen's many Matrix member functions are available too, but in free function
form (since it wouldn't make sense to add these members to Quantity). Instead
of x.norm(), you would write norm(x), and so on. (#688, #720)
Also implemented in: #683, #687, #691, #695, #696, #697, #736.
✨ CUDA is now supported natively (#671)
Au types now work in CUDA (and HIP) device code. We added macros to all of our
API functions, quantity makers (meters, ...), prefix appliers (kilo, ...),
unit symbols (yd, ...), and the library's constants, which apply the
__host__ and __device__ annotations as appropriate. Magnitude labels
can't be device-callable (since they return references to static host memory),
but we have good library coverage otherwise.
Implemented in: #628, #673, #674, #700.
✨ Arithmetic and comparison support for Constant and Magnitude (#607)
Constant and Magnitude used to support multiplication and division, but not
much else. Now, wherever the operation is well defined and exact, both of
them support the full complement of arithmetic and comparison operators:
comparison, including the C++20 spaceship operator (#642, #644, #649, #650);
addition and subtraction (#643, #652, #657); the modulus operator %
(#645, #653); and the rounding operators (#647), including support in all of
the rounding functions (#531, #648). Constant additionally supports unary plus
(#651). Zero participates throughout, with Magnitude-like ergonomics (#646)
and comparison against a Constant (#668). Finally, a Magnitude can now be
passed to a unit slot, so anywhere you could multiply or divide by a Constant,
you can use the equivalent Magnitude instead (#699).
We also filled in the integer-rounding gap (#243): round_in, floor_in, and
friends now have int-based (#637) and explicit-rep (#639) forms, consolidated
behind a common implementation (#641).
Also implemented in: #640, #654, #656.
✨ User-defined literals for Constant and Magnitude
We now provide UDLs that produce exact values. 3_mag gives you
a Magnitude (#677), and it understands decimal points and scientific notation:
1.5_mag is an exact rational, which is a big ergonomic improvement over having
to write 3_mag / 2_mag (#694).
Building on that, every unit gets a Constant-producing UDL of its own (#698):
1.28e-4_m is equivalent to make_constant(1.28e-4_mag * meters). These live
in per-unit headers under "au/units/literals/", so you only pay compile time
for the ones you actually include. The one weakness of UDL-based constants used
to be that they didn't compose the way unit symbols do; we fixed that (#727),
so you can build up compound constants from literals. For guidance on choosing
between literals and unit symbols, see our new discussion doc on abbreviated
quantity construction (#738).
✨ Ergonomic integer division: divide_using_common_unit() (#555)
Integer division of two same-dimension quantities is one of Au's most common
sources of friction, and unblock_int_div is a blunt instrument. The new
divide_using_common_unit(a, b) utility (#558) is almost always what people
actually want: it converts both inputs to their common unit and divides, giving
a plain integer answer with no silent truncation surprises. It is a safe,
idiomatic replacement for most unblock_int_div use cases, and the
troubleshooting guide now recommends it.
Other enhancements, bugfixes, and refactorings
- Implicit
Quantityconstructors no longer usestatic_castinternally, which
had been suppressing some compiler warnings (#528, #629, #631, #633) - Conversion risk policy objects (the results of
ignore(...)andcheck_for(...))
can now be combined and modified directly, instead of forcing users to write
custom trait structs that reach intodetail(#662, #663) - We now assume that multiplying by an integer can never truncate (#706) ---
it can only overflow --- which unlocks a meaningful set of non-arithmetic rep
use cases at no cost in safety q.as<T>()andq.in<T>()syntax (with no unit argument) now works for
quantities and points, for pure rep conversions (#256, #626)- Version macros:
AU_VERSION,AU_VERSION_MAJOR,AU_VERSION_MINOR,
AU_VERSION_PATCH, andAU_VERSION_NUMBER(major, minor, patch)are available
from any Au header, so downstream code can detect Au's presence and version
(#667, #702) minandmaxnow share a common implementation, so their (corrected)
semantics apply consistently everywhere (#680)- New rep-named aliases for small integers:
QuantityI8,QuantityU8,
QuantityI16,QuantityU16, and theQuantityPointequivalents (#722) - Compiler errors now name the actual unit (
Quantity<au::Meters, ...>instead
ofQuantity<Unit, ...>), because our templates refer toUnitT(#728) isinf(q)is now supported (#545, #551)QuantityPointcan now be formatted with {fmt} andstd::format(#552, #604)- Every unit definition is now fully independent, so each unit include file
brings in only what it needs. This also resolves a GCC 10.2.0 internal
compiler error in theNewtonsdefinition (#451, #560, #602, #606) - Improved efficiency of compile-time factorization, expanding the set of
numbers we can factor without hitting theconstexprstep limit (#328, #686) Constantrepresentability checks now SFINAE out, instead of hard-erroring,
when invoked on different-dimension units (#669)- More Green Hills MULTI accommodations: an unreachable return in
GetValueResultImplForDefaultCase(#664, #665), and a ternary rewrite (#670) - Removed the unused
MagTypemachinery (#623) - Large internal renaming sweep to eliminate names that differ only by a
T
suffix, usingPackandImplsuffixes instead (#86, #610, #611, #613, #614,
#616, #617, #618, #619, #620, #621, #622, #624, #625)
Compile time impact
We tested four Aurora-internal targets, and measured them hundreds of times on
0.5.1 and 0.6.0. We found that the compile time impact varied from target to
target: we observed regressions of roughly 10 ms, 20 ms, 30 ms, and 130 ms.
New units and constants
Units:
astronomical_units(#659), with the symbolAU(spelled the older way, to
avoid confusion with our ubiquitousaunamespace)rankine(#608), with the symboldegR, extracted from where it had been
buried inside theFahrenheitdefinition since time immemorial
Tooling updates
- Single-file script supports UDLs, individually via
--literalsor all at once
via--all-literals. The "all units" pre-built files enable--all-literals
by default, so literals are available on godbolt (#724) - Single-file script now respects guarded includes, leaving them inside their
#ifblocks rather than hoisting them unconditionally to the top, which broke
builds on compilers lacking the guarded header (#729) - Fixed
au-docs-serveauto-refresh by explicitly passing--livereload
(#635, #636) - Got clang-format working again with the updated toolchains (#585, #584), and
made CI and local runs use the same version (#703)
Documentation updates
Alternatives page
- Added a section on ongoing maintenance, so readers can weigh how actively each
library is being developed (#532, #541) - Filled in the compile time row for every library, based on a first complete
head-to-head assessment across all five (#704). - Refreshed the whole page for 0.6.0, including coverage of the newly-default
3.x branch of the nholthaus library (#731).
Everything else
- New Eigen documentation: a how-to guide, a reference page, and a discussion
page on expression template safety. We also updated the remaining doc pages
to reflect vector and matrix support, and the new implicit-rep semantics
(#713) - Refreshed the overflow and truncation discussions in light of Eigen
(#70, #721) - New "examples" section: small, complete, runnable programs showing what
migrating to Au does to real code. Each is inlined into its doc page via
snippets, and CI verifies that the raw and Au versions produce identical
output (#529, #726). The examples so far:- Angular velocity (#726)
- Hartree atomic units, our first example of defining a new system
(#660, #730) - ADC readings: our first embedded use case, showing off integer
arithmetic handling (#735) - Eigen kinematics, showing how much Eigen code simplifies with automatic
unit conversions and library constants (#737)
- New discussion doc on abbreviated quantity construction: how the unit symbol
and unit literal features evolved, and how to choose between them (#738) - Documented our compiler warnings policy (#528, #725)
- Documented the UDLs, and made them available from the installation
instructions (#724) - Reflected CUDA support in the docs (#671, #675)
- Updated the install instructions for bzlmod (#689)
- Updated the troubleshooting guide for the 0.6.0 error messages (#732)
- Updated the warning in the "new units" how-to guide (#609)
- Added a
usingdirective to the godbolt links (#540) - Fixed badge alignment in the README (#576)
Repo updates
Bazel 8 and bzlmod (#485)
We migrated the whole repo to bzlmod, and to Bazel 8. This touched nearly every
dependency, and every toolchain: bazel_skylib, googletest, rules_python,
rules_go, nholthaus units, {fmt}, buildifier, and the LLVM and GCC toolchains.
We now use platforms to manage compiler versions, mark dev-only dependencies as
such, and --- at long last --- have deleted WORKSPACE altogether. Along the
way, clang 17 became our default compiler (#487), and we now test against both
the newest and the oldest GCC that our toolchain offers.
We also added CI coverage for client projects in all the relevant
configurations, so this can't silently break again: bzlmod-based clients,
WORKSPACE-based clients, and clients that bring their own non-standard
googletest.
Implemented in:
- #534, #535, #536, #537, #538, #539, #543, #546, #547, #561, #562, #563, #564,
#565, #566, #567, #568, #569, #570, #571, #572, #573, #574, #575, #577, #578,
#579, #580, #486, #601, #603, #615, #630, #634, and #638.
Everything else
- New CI coverage: CUDA builds (#672), ASAN and UBSAN (#678), MSVC on Windows
Server 2025 (#442, #600), and//au:std_format(#508, #599) - Test hygiene: test suite names now follow the GoogleTest style guide (#586),
numeric_limitstests check againststd::numeric_limits(#587), tests are
split by-Wconversionstatus (#632), fixtures use constructors rather than
SetUp(#693), and theConstantlabel matcher was fixed (#655) - Added RELEASE procedures for "problem" compilers (#550)
- Updated python packages (#583) and
requirements_lock.txt(#612)
Future-proofing releases
-
🚀
0.6.0-future-714: release covering #714- This commit removes all APIs with the word "coerce" in their name. To fix
build errors, first, delete thecoerce_part of the name. Then, if you
get a compiler error, read the error to see what risk set the library has
flagged, and refer to our conversion risk guide
https://aurora-opensource.github.io/au/0.6.0/troubleshooting/#risk-too-high
to see how to handle this specific instance.
- This commit removes all APIs with the word "coerce" in their name. To fix
-
🚀
0.6.0-future-715: release covering #715- This commit makes
ScalarOfTraitspecialization required for every type
that doesn't already work automatically. See our trait specialization docs
https://aurora-opensource.github.io/au/0.6.0/reference/rep/#specializing-scalaroftrait
for more details.
- This commit makes
-
🚀
0.6.0-future-733: release covering #733- This commit deletes all "
T-suffixed" names (e.g.,UnitProductTinstead
ofUnitProduct) from the library. The fix is generally to use the version
without theTsuffix.
- This commit deletes all "
Closed Issues
Here are all of the issues that were closed since the last release.
Contributors
Thanks to those who authored or reviewed PRs, or filed or participated in
Issues! Alphabetically:
- @ar4nud65
- @avrahamshukron
- @chiphogg
- @geoffviola
- @ghorn
- @hoffbrinkle
- @hwiesmann
- @marzer
- @matthew-reynolds
- @nkiraly
- @rootshellz
- @SagaciousB
- @StefanoD
- @timhirsh
- @vilchanskyio-work
Artifacts and SHA256 sums
| Artifact | Role | SHA256 sum |
|---|---|---|
au-0.6.0.tar.gz |
Main release | e03aba27139b1e090b520945e62fc3ba2bf9128a096d68576eaf301970d5fb10 |
au-0.6.0-future-714.tar.gz |
Future-proof for #714 | 9a14ce3227fd27dd836b477aef76c1a008dbc8cfbce4ffb91c0852cfc4b4f2b3 |
au-0.6.0-future-715.tar.gz |
Future-proof for #715 | 93f75680fd7ebb94ade1c354cc524915bc5d32c1b2356f310732c7972cbcaa32 |
au-0.6.0-future-733.tar.gz |
Future-proof for #733 | 401e5bc41738bd1dd72bb9f8f3e68a58585d5f29a03938a05d97851d9110f6f5 |
au-0.6.0-future.tar.gz |
Complete future-proof release | 28e2fb30040ece6dd7087d2500a2d78944ed8407e454268eb89748564a988c6f |