Skip to content

0.6.0

Latest

Choose a tag to compare

@chiphogg chiphogg released this 26 Aug 19:17
· 0 commits to main since this release

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::UnitAvoidance specializations are no longer permitted;
    specialize au::UnitOrderTiebreaker instead. (#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 a Quantity. 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_as and coerce_in are deprecated everywhere. Instead of
    coerce_as(u), use as(u). If it fails to compile, read the error, and use
    one of as(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 of q.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 write q.as<au::SameRep>(u) to request the same rep explicitly.
    (#679, #685, #712, #719)

  • The Quantity constructor now performs an implicit conversion on the
    underlying value, rather than a static_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 as m[B^(-1)], rather than the
    ambiguous mB^(-1). Brackets are omitted where they'd add nothing (so
    centi(meters / seconds) is still cm / 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 Quantity constructors no longer use static_cast internally, which
    had been suppressing some compiler warnings (#528, #629, #631, #633)
  • Conversion risk policy objects (the results of ignore(...) and check_for(...))
    can now be combined and modified directly, instead of forcing users to write
    custom trait structs that reach into detail (#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>() and q.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, and AU_VERSION_NUMBER(major, minor, patch) are available
    from any Au header, so downstream code can detect Au's presence and version
    (#667, #702)
  • min and max now share a common implementation, so their (corrected)
    semantics apply consistently everywhere (#680)
  • New rep-named aliases for small integers: QuantityI8, QuantityU8,
    QuantityI16, QuantityU16, and the QuantityPoint equivalents (#722)
  • Compiler errors now name the actual unit (Quantity<au::Meters, ...> instead
    of Quantity<Unit, ...>), because our templates refer to UnitT (#728)
  • isinf(q) is now supported (#545, #551)
  • QuantityPoint can now be formatted with {fmt} and std::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 the Newtons definition (#451, #560, #602, #606)
  • Improved efficiency of compile-time factorization, expanding the set of
    numbers we can factor without hitting the constexpr step limit (#328, #686)
  • Constant representability 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 MagType machinery (#623)
  • Large internal renaming sweep to eliminate names that differ only by a T
    suffix, using Pack and Impl suffixes 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 symbol AU (spelled the older way, to
    avoid confusion with our ubiquitous au namespace)
  • rankine (#608), with the symbol degR, extracted from where it had been
    buried inside the Fahrenheit definition since time immemorial

Tooling updates

  • Single-file script supports UDLs, individually via --literals or 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
    #if blocks rather than hoisting them unconditionally to the top, which broke
    builds on compilers lacking the guarded header (#729)
  • Fixed au-docs-serve auto-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 using directive 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:

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_limits tests check against std::numeric_limits (#587), tests are
    split by -Wconversion status (#632), fixtures use constructors rather than
    SetUp (#693), and the Constant label 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 the coerce_ 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.
  • 🚀 0.6.0-future-715: release covering #715

  • 🚀 0.6.0-future-733: release covering #733

    • This commit deletes all "T-suffixed" names (e.g., UnitProductT instead
      of UnitProduct) from the library. The fix is generally to use the version
      without the T suffix.

Closed Issues

Here are all of the issues that were closed since the last release.

https://github.com/aurora-opensource/au/issues?q=is%3Aissue%20closed%3A2025-08-20..2026-08-26%20-milestone%3A0.5.1%20-milestone%3A0.5.0

Contributors

Thanks to those who authored or reviewed PRs, or filed or participated in
Issues! Alphabetically:

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