Skip to content

Conversation

@chiphogg
Copy link
Member

Right now, conversion failures are somewhat inscrutable. Consider these
unsafe conversions:

seconds(2).as(nano(seconds));                      // OVERFLOW_RISK
nano(seconds)(2).as(seconds);                      // TRUNCATION_RISK
(giga(hertz) * mag<2>() / mag<3>())(1).as(hertz);  // ALL_RISKS

I've annotated each one with the risk that prevents the conversion ---
but remember that an end user won't know a priori which one this is!
And the error messages are no help:

image

This just basically says "some risk is too high". It doesn't say which
risk(s), and it doesn't say what to do about it.

We can do better by checking the risks individually, and splitting the
error message across three mutually exclusive and exhasutive error
conditions. First, if a conversion is blocked, then it would either
fail the overflow risk check, truncation risk check, or else both (those
are the 3 possibilities). Second, if any non-skipped risk check
fails, then we want to check all risk checks, regardless of skip
status. After all, if a conversion is "double risked", and the user has
passed ignore(OVERFLOW_RISK), we don't want to tell them to pass
ignore(TRUNCATION_RISK), because that will just re-activate the
overflow risk failure! We want to tell them to use ignore(ALL_RISKS).

image

These error messages are much more clear and actionable. We can
bikeshed the wording, but it seems clear that this will be a much better
experience for our users.

Follow-on to #387.

Right now, conversion failures are somewhat inscrutable.  Consider these
unsafe conversions:

```cpp
seconds(2).as(nano(seconds));                      // OVERFLOW_RISK
nano(seconds)(2).as(seconds);                      // TRUNCATION_RISK
(giga(hertz) * mag<2>() / mag<3>())(1).as(hertz);  // ALL_RISKS
```

I've annotated each one with the risk that prevents the conversion ---
but remember that an end user won't know a priori which one this is!
And the error messages are no help:

<img width="1117" height="829" alt="image"
src="https://github.com/user-attachments/assets/8f0315be-dd03-44d8-876d-ba71577633f9" />

This just basically says "some risk is too high".  It doesn't say which
risk(s), and it doesn't say what to do about it.

We can do better by checking the risks individually, and splitting the
error message across three mutually exclusive and exhasutive error
conditions.  First, if a conversion is blocked, then it would either
fail the overflow risk check, truncation risk check, or else both (those
are the 3 possibilities).  Second, if _any_ non-skipped risk check
fails, then we want to check _all_ risk checks, _regardless_ of skip
status.  After all, if a conversion is "double risked", and the user has
passed `ignore(OVERFLOW_RISK)`, we don't want to tell them to pass
`ignore(TRUNCATION_RISK)`, because that will just re-activate the
overflow risk failure!  We want to tell them to use `ignore(ALL_RISKS)`.

<img width="1117" height="814" alt="image"
src="https://github.com/user-attachments/assets/8a9ac4a4-5eeb-4b0b-aac1-7af6e98bac84" />

These error messages are much more clear and actionable.  We can
bikeshed the wording, but it seems clear that this will be a much better
experience for our users.

Follow-on to #387.
@chiphogg
Copy link
Member Author

I'm planning to kick off an overnight compile time impact measurement tonight. We can review the PR once we get those results.

@chiphogg chiphogg marked this pull request as ready for review July 24, 2025 14:45
@chiphogg
Copy link
Member Author

The compile time impact is roughly:

  • No impact on the cost to include the file
  • Non-negligible impact on the cost of conversion functions

0.5.0 already has a moderate slowdown for conversion functions generally. It's higher than I would prefer, but not a showstopper IMO. What this PR seems to do is to make that increased cost about 15% larger. This is also higher than I would prefer, but I think the usability gains are worth more. Even in our canonical "lots of conversions" file, this PR amounts to about 25 ms (cumulative over all those conversions). I think that is a price worth paying to make the error messages significantly more actionable.

As for the specific contents of the message:

  • The best "final form" would be a link to the troubleshooting page, plus an indication of which risk policy to pass in this specific case.
  • We already need to do a complete pass through the troubleshooting page for 0.5.0 anyway, and this change will get picked up automatically in the course of doing that.
  • It doesn't make sense to land a link to a URL that doesn't exist yet (because we link to the section, and the section name will change).

So I think we can land as-is as a placeholder, with plans to fix up the contents when we do the doc refresh.

au/quantity.hh Outdated
!is_truncation_risk_ok;
static_assert(!are_both_overflow_and_truncation_unacceptably_risky,
"Both truncation and overflow risk too high. "
"Can silence by passing `ignore(ALL_RISKS)` as second argument, "
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Just had a thought about ALL_RISKS. Would there be a passibility that we'll add additional risk types in the future? Would setting ALL_RISKS today potentially mask those new risks in the future?

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think it's pretty unlikely, but I definitely think this will be safer, and at the very least also more intent-based. I'll update the message accordingly.

@chiphogg chiphogg merged commit 645a106 into main Jul 24, 2025
14 checks passed
@chiphogg chiphogg deleted the chiphogg/say-which-one#387 branch July 24, 2025 21:56
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants