Skip to content

Commit

Permalink
Improve error message for Quantity in unit slot (#366)
Browse files Browse the repository at this point in the history
This is an easy mistake to make for users who haven't yet grasped the
idioms of the library.  Now, if they do this, they'll get a nice,
readable error, which directs them to the new section of the
troubleshooting doc (also added in this PR) that explains what is going
wrong, and what to do about it.

Fixes #327.
  • Loading branch information
chiphogg authored Dec 19, 2024
1 parent 8165cb6 commit a3fad06
Show file tree
Hide file tree
Showing 5 changed files with 328 additions and 0 deletions.
16 changes: 16 additions & 0 deletions au/code/au/quantity.hh
Original file line number Diff line number Diff line change
Expand Up @@ -424,6 +424,22 @@ class Quantity {
Rep value_{};
};

// Give more readable error messages when passing `Quantity` to a unit slot.
template <typename U, typename R>
struct AssociatedUnit<Quantity<U, R>> {
static_assert(
detail::AlwaysFalse<U, R>::value,
"Can't pass `Quantity` to a unit slot (see: "
"https://aurora-opensource.github.io/au/main/troubleshooting/#quantity-to-unit-slot)");
};
template <typename U, typename R>
struct AssociatedUnitForPoints<Quantity<U, R>> {
static_assert(
detail::AlwaysFalse<U, R>::value,
"Can't pass `Quantity` to a unit slot for points (see: "
"https://aurora-opensource.github.io/au/main/troubleshooting/#quantity-to-unit-slot)");
};

////////////////////////////////////////////////////////////////////////////////////////////////////
// Machinery to explicitly unblock integer division.
//
Expand Down
16 changes: 16 additions & 0 deletions au/code/au/quantity_point.hh
Original file line number Diff line number Diff line change
Expand Up @@ -282,6 +282,22 @@ struct QuantityPointMaker {
template <typename U>
struct AssociatedUnitForPoints<QuantityPointMaker<U>> : stdx::type_identity<U> {};

// Provide nicer error messages when users try passing a `QuantityPoint` to a unit slot.
template <typename U, typename R>
struct AssociatedUnit<QuantityPoint<U, R>> {
static_assert(
detail::AlwaysFalse<U, R>::value,
"Cannot pass QuantityPoint to a unit slot (see: "
"https://aurora-opensource.github.io/au/main/troubleshooting/#quantity-to-unit-slot)");
};
template <typename U, typename R>
struct AssociatedUnitForPoints<QuantityPoint<U, R>> {
static_assert(
detail::AlwaysFalse<U, R>::value,
"Cannot pass QuantityPoint to a unit slot (see: "
"https://aurora-opensource.github.io/au/main/troubleshooting/#quantity-to-unit-slot)");
};

// Type trait to detect whether two QuantityPoint types are equivalent.
//
// In this library, QuantityPoint types are "equivalent" exactly when they use the same Rep, and are
Expand Down
9 changes: 9 additions & 0 deletions au/error_examples.cc
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@
// limitations under the License.

#include "au/au.hh"
#include "au/units/bytes.hh"
#include "au/units/feet.hh"
#include "au/units/hertz.hh"
#include "au/units/hours.hh"
Expand Down Expand Up @@ -69,6 +70,14 @@ void example_no_type_named_type_in_std_common_type() {
meters(1) + seconds(1);
}

////////////////////////////////////////////////////////////////////////////////////////////////////
// SECTION: Can't pass `Quantity` to a unit slot

void example_cant_pass_quantity_to_unit_slot() {
auto size = bytes(1234);
size = round_as<int>(bytes(10), size);
}

////////////////////////////////////////////////////////////////////////////////////////////////////
// SECTION: Integer division forbidden

Expand Down
10 changes: 10 additions & 0 deletions docs/discussion/idioms/unit-slots.md
Original file line number Diff line number Diff line change
Expand Up @@ -193,6 +193,16 @@ The reason we endorse the `QuantityMaker` overloads is because of the convention
a new `QuantityMaker` on the fly, then this benefit vanishes. (This is why unit expressions are
preferred for generic code.)

## What _doesn't_ fit in a unit slot?

A `Quantity`! It can certainly be tempting, as in some ways a `Quantity` can "feel like" a unit.
However, the `Quantity` also has a _runtime value_ attached. By contrast, unit slots can only take
things that have a single, unambiguous value, known _at compile time_.

Fortunately, if you make this mistake, you'll get a readable compiler error that directs you to [our
troubleshooting page](../../troubleshooting.md#quantity-to-unit-slot), so you can learn more about
why this isn't allowed, and what you can do to fix it.

## Summary

Many Au APIs have a "unit slot". These are designed for you to name the units explicitly at the
Expand Down
Loading

0 comments on commit a3fad06

Please sign in to comment.