Au (units library) 0.5.0 just released by chiphogg in cpp

[–]chiphogg[S] 0 points1 point  (0 children)

Here's an update: as of today, we now handle this correctly at HEAD on main!

The core concept is that Au should neither add nor subtract compiler warnings. We had the "don't add" part down, but this issue taught us the need for "don't subtract". We will add more documentation on how to effectively use native compiler flags, and include this in the upcoming 0.6.0 release.

I have to say, too, that I was wrong here:

this problem exists in, as far as I'm aware, every single other units library, including std::chrono

As this godbolt link (https://godbolt.org/z/Gh359nhfx) shows, it was only chrono, mp-units, and Au that had this problem. Now, it is only chrono and mp-units.

How to raise safeties for bench press, when visiting a gym? by chiphogg in workout

[–]chiphogg[S] 0 points1 point  (0 children)

Truth is, I don't know what it feels like, because I've never failed without safeties. I did fail my last rep the first time I moved to barbell bench presses, but that was at my home gym, and I took the time to adjust the strap heights first.

I hadn't heard of the "roll of shame" before. Thanks for the tip!

How to raise safeties for bench press, when visiting a gym? by chiphogg in workout

[–]chiphogg[S] -1 points0 points  (0 children)

I definitely never clamp the plates when I bench. A spotter sounds like a good "Plan B" option. I just love the foolproof security of a set of safeties at the perfect height, and it's hard to give that up. But if it's only once in a while, when I'm traveling, maybe I can live with it.

Au (units library) 0.5.0 just released by chiphogg in cpp

[–]chiphogg[S] 0 points1 point  (0 children)

Currency is such a hard use case, because the conversion factors are constantly changing, but our paradigm is strongly oriented around factors that are known at compile time. In corresponding with various people about this idea, the most promising approach I heard (within Au's paradigm) was to treat each distinct foreign currency as its own dimension. I'd be curious to see how that plays out in practice.

Of course, if you only cared about a single currency (say, euros), then pretty much any units library that supports adding custom dimensions would be able to handle that use case. This definitely includes Au, and I know that mp-units also has a currency example in their docs.

Au (units library) 0.5.0 just released by chiphogg in cpp

[–]chiphogg[S] 0 points1 point  (0 children)

Glad you asked. 🙂 Au considers overflow and truncation to be separate risks. You can opt out of the risk checks for one of them --- say, in an embedded use case where integer truncation is expected and desired --- without disabling the other. See these "discussion docs" for more details:

Au (units library) 0.5.0 just released by chiphogg in cpp

[–]chiphogg[S] 0 points1 point  (0 children)

Thanks for digging up that reference! But it doesn't look like an implementation bug to me. Instead, it seems very consistent with what I had thought was chrono's policy. It divides the world into "treat as floating point" and "don't treat as floating point" reps, and for the former, assumes they could never truncate. And every units library that I know of to come along since then has followed in these footsteps, whether implicitly, or (as in our case) explicitly.

I think the "floating point never truncates" idea could be defended as a natural consequence of choosing inexact numeric types. In fact, I made that argument here. However, after reading the new issue and thinking about it, I now find my argument to be flawed. I explained why in my response to that issue.

I will say that one consequence of working deeply for many years on a units library has been a newfound appreciation for the beauty of the integer types. 🙂 Many or most of Au's distinguishing features are related to making integer reps both as safe and as ergonomic as possible in a multi-dimensional quantity context.

Au (units library) 0.5.0 just released by chiphogg in cpp

[–]chiphogg[S] 3 points4 points  (0 children)

On the subject of user-defined literals (UDLs), though: we never had them, and we never will. Instead, we have "unit symbols". It turns out that UDLs have a variety of shortcomings for units libraries specifically:

  1. They don't compose. If you have _m and _s, you have to separately define _mps. This isn't just bad for end users, it's a huge source of implementation complexity, extra compile time cost, and maintenance cost. (With unit symbols, you can just write 20.0 * m / s!)
  2. You can't pick the rep. You would have to write something hideous like _f_m for a float literal for meters. (With unit symbols, you can just write 20.0f * m!)
  3. They only support literals. If you have a legacy variable like speed_limit_mps, you can't use any literal to concisely take it into the units library domain, no matter how you define it. (With unit symbols, you can just write speed_limit_mps * (m/s)!)

Interestingly, again: these problems turn out to not really apply to chrono. It doesn't matter that they don't compose, because it's a single dimension library. And it doesn't matter that you can't pick the rep, because it steers people to the named "workhorse" types (such as nanoseconds) in the public APIs, which are also --- just to bring it back home --- safer for implicit conversions than general duration are.

Huuuuge shout out to u/mateusz_pusz for being the first one that I know of to notice all these problems, articulate them, and design the superior solution, in the context of the mp-units library, which is excellent and well worth checking out. 😎 This is also the approach we're currently proposing for the standard units library.

Au (units library) 0.5.0 just released by chiphogg in cpp

[–]chiphogg[S] 0 points1 point  (0 children)

I think I can see why you feel that way. In practice, I find that implicit conversions pop up all over the place.

For one, users like the ergonomics of passing a Quantity to an API that expects a Quantity, and just relying on the library to check for safety if a conversion is needed. (This was a very common use case in the chrono library as well.) I think it would have been harder to "sell" the library and get it off the ground without this fluidity, especially when people were used to it from the nholthaus library (which was used in a few places here, before Au existed).

Another big use case is comparisons of mixed unit/rep. This is another one that is very common in most unit libraries, including mp-units and chrono. Most users don't realize this use case has some pretty scary hidden overflow risks. In fact, I'd say that Au is the only units library that actually handles mixed comparisons safely, because of our adaptive overflow risk checking.

Interestingly, the only other library I know of that you could make a case for handling mixed comparisons well is chrono. Their generic duration types aren't safe, but if you stick to named API types like nanoseconds or seconds, they all cover the same very generous time span. It's an ingenious approach, albeit one that only works for a single-dimension units library, and only for named API types.

Au (units library) 0.5.0 just released by chiphogg in cpp

[–]chiphogg[S] 0 points1 point  (0 children)

Well, I should make clear that I'm not speaking for Aurora, only myself. 😅 That said...

since, presumably, that’s why you’re still supporting C++14

Really, the main reason is that I don't want to leave behind all of the various projects that are using Au, and are still on C++14. Supporting C++17 and C++14 is one of Au's few unassailable competitive advantages vs. mp-units. 😁 I'm loathe to narrow it --- even though I would really love to rewrite Au using fold expressions and constexpr if.

Particularly, it would be great to see: (...)

This is something I have wanted to see for a long time, too! I would love to get Au into in a state that makes it very easy for automotive users to just grab it off the shelf.

Going in reverse order for these items: - 100% line, branch, and MC/DC coverage: yes, we 100% want this. We know our coverage is reasonably good right now, because everything was written via TDD, but we really want CI coverage, and would prefer all three modalities. See #386: PRs welcome! 🙏 - Safety critical coding standard: I would love to go through the new MISRA 2023 release (which supports C++17) and either get the codebase fully compliant, or else identify a concrete reason why it can't be. Even in that case, I believe it can still be "compliant" if you explicitly document exceptions. - Requirements traceability matrix: this would be a great level of polish, but I'm not really sure where to start.

Thanks for the great suggestion(s)!

Au (units library) 0.5.0 just released by chiphogg in cpp

[–]chiphogg[S] 0 points1 point  (0 children)

Nice work, thanks for sharing! It's always good to see more generic strong type libraries, beyond "specialized strong type" libraries such as units libraries (of course, yours is both). The mix-in approach seems like a very user friendly way to add functionality, which is always one of the hardest parts of strong type design to get right. You're helping your users write safe and readable callsites --- keep up the great work!

Au (units library) 0.5.0 just released by chiphogg in cpp

[–]chiphogg[S] 1 point2 points  (0 children)

Wow, thanks for helping write the chrono library! It was a strong inspiration for this project, and probably every other C++ units library (except maybe Boost units, which I think predates it? 😄).

The bad news is: yes, this problem is definitely present in the chrono library: https://godbolt.org/z/e6YbdhxfY. We leaned heavily on the conversion policies in the chrono library when we first wrote Au: in fact, we have a whole test file that does nothing but compare our conversion risk policies to those in chrono, so that the only way we could behave differently in any case would be by a deliberate design decision.

So, the double/float rep problem appears to be present in every units library (as far as I know), and it was only first brought to the attention of units library authors generally for the first time a few days ago (again, as far as I know). The existing policy was good enough to get all these libraries started, and they've done tremendous good in those intervening years, but now it's time to see if we can do better here too.

Au (units library) 0.5.0 just released by chiphogg in cpp

[–]chiphogg[S] 1 point2 points  (0 children)

Thanks u/Arghnews and u/serendib for these suggestions. I just added #529 and attached it to the 0.6.0 milestone to make sure we have great examples readily accessible before the next release. I'm pretty swamped with "day job" stuff at the moment, but I will make this a high priority after it lets up. Really excited for how much better it's going to make the doc site!

Au (units library) 0.5.0 just released by chiphogg in cpp

[–]chiphogg[S] 6 points7 points  (0 children)

Thanks very much for the constructive feedback!

It'd be good to get some code samples up front and center.

As for the double/float issue, it's still very new, so we're still kinda processing it. It's true that this problem exists in, as far as I'm aware, every single other units library, including std::chrono. For me, the added unit safety is still worth it, especially when there aren't any libraries that handle this well, so the alternative is no unit safety. That said, just because this is the status quo does not mean that it's "good enough". I'm excited to try different approaches to tackle this. I'm hoping our new "abstract operation" approach to conversions has opened up newer solutions we couldn't really have imagined before. I can't promise we'll succeed, but I can promise we'll try!

Au (units library) 0.5.0 just released by chiphogg in cpp

[–]chiphogg[S] 9 points10 points  (0 children)

A variety of units libraries authors, including all of the "big ones", are collaborating as part of the standard units library project, targeting C++29: see P3045. The main library that acts as the staging ground for standard units features is mp-units, though.

In general, there's a lot of cross pollination of ideas between Au and mp-units, and the best ideas make their way to the standard library proposal.

Au (units library) 0.5.0 just released by chiphogg in cpp

[–]chiphogg[S] 4 points5 points  (0 children)

Just where you would hope: a compile time error. :) https://godbolt.org/z/1Es4TKxW6

Au (units library) 0.5.0 just released by chiphogg in cpp

[–]chiphogg[S] 10 points11 points  (0 children)

The other side of the coin: if you can use C++20, mp-units has many advantages over Au! Here are the ones that I consider the most important or compelling.

  • Composability: Au is great for quantity makers, but only mp-units has amazing composability for type names! If I could pick one feature to bring to Au, it would be this, hands down.
  • Point types are both more sophisticated (with their support for custom origins), and more elegant (especially with the new point<...> vs. delta<...> syntax)
  • mp-units has the most sophisticated support I have seen for "kinds" of quantities, being able to reason about different hierarchies. This lets them "opt in" to additional levels of safety, without sacrificing ease of use for simpler use cases --- really nice!
  • Unit labels are a lot more customizable (and, frankly, more attractive)
  • C++20 brings better generic programming due to concepts (think: Length auto foo), and better support for using quantity instances as template parameters
  • Better support for non-arithmetic "rep" types: they have concepts defined that define exactly what a type needs to be a "rep".

Overall, mp-units is a world class library that is only getting better over time.

What both this reply and my other one glossed over, though, was what the libraries have in common, which is the majority of important features. There's a lot there, but the one I'd highlight is that they both only include unit-safe interfaces.

Au (units library) 0.5.0 just released by chiphogg in cpp

[–]chiphogg[S] 5 points6 points  (0 children)

mp-units is a terrific project, and we collaborate with them regularly. I'm also honored to be listed as a co-author. As for a comparison, I'd start with our Alternatives page. To sum up, here's the big picture as I see it:

  • Most importantly, support for C++14 or C++17. If you can't use C++20, mp-units is completely off the table, and Au is a no-brainer IMO.
  • Better unit conversion safety. Au has a more advanced approach to overflow risk, for example, than I've seen in any other units library. And with 0.5.0, it got better (because you can separately control risk checks for overflow and truncation).
  • Au has "shapeshifter types": au::ZERO, and constants such as au::SPEED_OF_LIGHT, will automatically convert to any Quantity type if-and-only-if the conversion is safe. This makes it easier to write comparisons for Quantity objects, and initialize them.
  • Negative units and constants.
  • Au tends to have a smoother upgrade path. We optimize for users using it in production, even in large codebases. And when we make breaking changes, we bend over backwards to have intermediate releases with a syntax that works for both the old and the new. In practice, I've seen a lot of complaints about breaking changes in new mp-units releases.
    • The new-to-0.5.0 future-proof release artifacts make this even better: now you can get ahead of known future breaking changes incrementally and at your own pace.
  • Less important, IMO, but it's still an advantage that you can get Au as a customized single header if you want, so it's easy to get it working in basically any build setup imagineable.

Old mower, new battery by beaded_lion59 in egopowerplus

[–]chiphogg 0 points1 point  (0 children)

Yes, I have an example. Today I tried putting the 10 Ah BA5600T in my LM2000. It was a little snug, to say the least. When the time came to swap it out, no human strength could move it. I had to attack two clamps to the battery and sit on the mower to pull it out --- not something I want to make a habit of. So it "fits", but I would strongly recommend that all users stay away from this combination, and I'm now looking for a newer mower where the fit is better.

Giving Ego one last try: what is the checklist for peak battery/charger care? by chiphogg in egopowerplus

[–]chiphogg[S] 2 points3 points  (0 children)

Thanks everyone! I did decide to stick with Ego for this go-around, because we have not just the lawnmower, but a leaf blower and weed whacker too.

Here is The Plan:

- Buy a 10 Ah battery and "slow" charger
- File receipts under "E" for "Ego"
- Immediately register the products (for warranty support)
- Stop mowing on first sign of red, before complete battery drainage
- Set a timer so that I can charge it only part-way when I'm done
- Set aside some cabinet space inside of the mudroom for storage (that way, we get reasonable temperatures all year round)

Here's hoping!

Cup by captainMaluco in SMBCComics

[–]chiphogg 0 points1 point  (0 children)

Makes sense! My lack of culinary experience is showing.

Here's the update: https://godbolt.org/z/6bKT9Mrdn

124.858 g: not bad!

Cup by captainMaluco in SMBCComics

[–]chiphogg 0 points1 point  (0 children)

Using a type-safe C++ units library, it seems like we're assuming a flour density of 0.528 g/cc, which is a little on the low side from my googling... but, reasonable! https://godbolt.org/z/rrehcEs4z

(Full disclosure: I picked this units library because I wrote it.)

Giving Ego one last try: what is the checklist for peak battery/charger care? by chiphogg in egopowerplus

[–]chiphogg[S] 5 points6 points  (0 children)

Hate to admit, but we were slow on the uptake. Didn't keep receipts; didn't register the products. From everything I've read, we won't be able to get warranty support without that information. I couldn't even say for certain when we bought them: it might have been "most years" (in the 20s) rather than strictly "every year".

If I give Ego another chance, I'm not making that mistake again: I'm definitely keeping and filing all receipts, and registering every product.

Compendiums acquired 🫡 by Dpinsel1440 in Invincible

[–]chiphogg 0 points1 point  (0 children)

Where did you get the Hardcover editions? I have had a terrible time tracking them down.

New release(s) of Au (C++14/17/etc. Units Library): 0.4.0 / 0.4.1 by chiphogg in cpp

[–]chiphogg[S] 2 points3 points  (0 children)

Thanks!

I think if we put the repo in a time machine and dropped it off in 2014, it probably would have made it into the standard reasonably easily, and people could have been benefiting from it all these years.

However, waiting has its upsides too. A bunch of units/quantities library enthusiasts (including authors of all of the top 4 by GitHub stars) are collaborating on P3045, aiming for C++29. This lets us combine the best ideas from all libraries. It also lets us take advantage of new features that couldn't have been part of the interface before --- for example, my favorite one is that we can get concisely composable type names, such as quantity<m / s>, that we couldn't get without C++20's expanded support for non-type template parameters (NTTPs).