> In your specific example, this would be less likely because you've included the full unit name in your alias. However, not everyone wants to do this --- often, people want to give it a more generic alias, like `temperature`. Preventing
this constructor from a single value (even when `explicit`), and making sure that every option forces the user to name the unit explicitly at the callsite, preserves unit safety, and reduces cognitive load.
I think you focused too much on the alias part, while the important part is a fully named type. In many codes bases the rule to explicit type out your types are a thing.
If I can fully type out the type that I want, why shouldn’t I be able to use it?
Why exactly do I need a separate gadget to create that type?
Talking about a mental effort, it is not enough to know the type that you want, you also need to lookup the right gadget (whose name has nothing to do with the type you are trying to construct) in order to construct your type,… what? Why?
Why? The principle is "unit safety" for interfaces. It's a core design principle for units libraries, which was pioneered by the
Au library, accepted and adopted in mp-units, and included in P3045. The "unit safety" principle depends on another principle, "unit correctness", which is one that people are more familiar with. Here are the definitions taken from the
Au 101 tutorial:
- Unit Correctness: a program is unit-correct when every variable associated with physical units is used consistently with those units.
- Unit Safety: a program is unit-safe when the unit-correctness of each line of code can be checked by inspection, in isolation.
The reason this is desirable is because it minimizes cognitive load. A unit-safe line does not guarantee that the program has no unit errors. It does mean that if there are unit errors, then they are in some other line (which you can also inspect). You can read a unit-safe line once, and be done with it!
The way to achieve this with a units library is to make sure that every interface that brings values into a units library type, or extracts values from a units library type, forces the user to name the unit explicitly, at the callsite. Au was designed with this approach in mind from the ground up, and I was very heartened to see mp-units adopt it as well, to the point that mp-units is now every bit the equal of Au in unit safety. (Really, the whole 2.0 redesign for mp-units was a stunning leap forward in a lot of ways --- I was thrilled to see it.)
Now to your question: if you have a typename that contains the unit name, isn't that enough? Say we had a type called `degrees_celsius`: why wouldn't it be OK to have a constructor from `double`, so you could simply write `degrees_celsius{42.0}`? (We would make it `explicit`, of course!)
One reason is the aliases, yes, but you've already explained why you don't find that persuasive. I still think it's valuable to expand the universe of safe use cases, so that people who want to refer to their type as `Temperature` can safely do so, but I could also imagine you simply proposing a rule that people should avoid such aliases. Fine.
However, even this is not enough. The "
explicit is not explicit enough" section which I linked to earlier already explains why. You could have something like this:
Ultimately, experience at scale shows that these unit-safe interfaces are easy to teach and learn, and effective at preventing unit-correctness errors.