Date: Tue, 18 Jun 2024 12:49:32 -0400
Hi! I joined the mailing list so that I could join in with this
discussion. Unfortunately, I have no idea how to reply to a message that
was already sent *before I got my membership*. So this reply is going to
be attached to the wrong message in the thread --- sorry about that!
For context: I'm the author of the Au units library, and a co-author on the
paper P3045 under discussion.
Tiago, thank you for providing a concrete example of a usability trap in
the library! Having a very specific example to work from will help us move
forward. Let's dig in and analyze this.
The core problem (as others have stated) is that there are two different
concepts that people might mean when they refer to "temperature". They
might mean "absolute" temperature ("what temperature is it?"), or they
might mean a temperature *difference*. It's critically important to know
which the user means, because they behave very differently! And we need to
support both --- this is simply a complication that we have inherited from
the underlying real-world subject matter.
Currently, both Au and mp-units have hit on the same solution: to provide
two abstractions, "quantity" and "quantity point". The chrono library has
analogous abstractions, in "duration" and "time point", so there's
precedent for this approach.
For units libraries, experience shows that "quantity" is almost always what
users want, as it supports the mathematical operations of quantity
calculus. Temperatures, though, are *very* different: in practice, we
often want "quantity point" (maybe even most of the time!).
I think the bar to meet here is that any code that users will naturally
tend to write should not silently produce incorrect results. How to do
that here? We *could* say "make quantity point the default for
temperature", but I think a better approach is "avoid *having* a default
for temperature". Here's how Au does this: users can write
`celsius_qty(20)` to get a *quantity* of 20 degrees Celsius, or
`celsius_pt` to get a *quantity point* representing a temperature of 20
degrees Celsius. If users write `celsius(20)`, this is defined, *but is
marked as `[[deprecated]]` with an error message that directs them to
`celsius_qty` and `celsius_pt`*, making them aware of the problem, and
telling them what solutions are available. See source code:
https://github.com/aurora-opensource/au/blob/221d8f41c41419bbdb585fb4cdea1217b8011fd1/au/units/celsius.hh#L37-L42
I think the idea of adding a "permanently deprecated" member to the
standard library, purely so that users can get a useful error message if
they try to use it, would be a very hard sell, and I'm not proposing it.
But I definitely think we need to avoid code that silently produces grossly
incorrect answers when used in the natural way. Maybe others can think of
a more palatable way to make users aware of the difficulty if they naively
try to do the wrong thing? Or maybe it's enough to simply omit the
"unadorned" names for temperatures.
By the way: as to the specific code example provided, the error is clearly
in the `28.0 * deg_C` expression. As others have pointed out, the
multiplicative syntax *necessarily* only works for quantity, never for
quantity point. Au also has "unit symbol" constructs that behave similarly
to the example. The way we handle it is to, again, omit the unadorned
name. Our unit symbol for degrees Celsius is `deg_C_qty`, putting its
nature front and center, and (I hope) suggesting to the end user that they
should understand why this symbol looks different from all the others.
On Tue, Jun 18, 2024 at 11:43 AM Ville Voutilainen via Std-Proposals <
std-proposals_at_[hidden]> wrote:
> On Tue, 18 Jun 2024 at 18:38, Mateusz Pusz via Std-Proposals
> <std-proposals_at_[hidden]> wrote:
> >
> > Multiply syntax will always create a quantity. So if I write:
> >
> > auto q = 4 * deg_C;
> >
> > I will end up with a delta temperature equal to 4 K.
> >
> > quantity q = 4 * deg_C; // the same thing as above
> >
> > If I try:
> >
> > quantity_point qp = 4 * deg_C;
> >
> > I will get a compile-time error as a quantity_point is not implicitly
> constructible from the quantity.
> >
> > To create a quantity_point, I have to do one of the following:
> >
> > quantity_point qp1 = zeroth_degree_Celsius + 4 * deg_C;
> > quantity_point qp2(4 * deg_C, zeroth_degree_Celsius);
> > quantity_point qp3(4 * deg_C); // proper point origin provided by
> default
> >
> > All of the above will create a temperature point with a value equal to
> 277.15 K.
>
> ..and chrono allows creating objects of such types with a literal,
> whereas this library doesn't?
> --
> Std-Proposals mailing list
> Std-Proposals_at_[hidden]
> https://lists.isocpp.org/mailman/listinfo.cgi/std-proposals
>
discussion. Unfortunately, I have no idea how to reply to a message that
was already sent *before I got my membership*. So this reply is going to
be attached to the wrong message in the thread --- sorry about that!
For context: I'm the author of the Au units library, and a co-author on the
paper P3045 under discussion.
Tiago, thank you for providing a concrete example of a usability trap in
the library! Having a very specific example to work from will help us move
forward. Let's dig in and analyze this.
The core problem (as others have stated) is that there are two different
concepts that people might mean when they refer to "temperature". They
might mean "absolute" temperature ("what temperature is it?"), or they
might mean a temperature *difference*. It's critically important to know
which the user means, because they behave very differently! And we need to
support both --- this is simply a complication that we have inherited from
the underlying real-world subject matter.
Currently, both Au and mp-units have hit on the same solution: to provide
two abstractions, "quantity" and "quantity point". The chrono library has
analogous abstractions, in "duration" and "time point", so there's
precedent for this approach.
For units libraries, experience shows that "quantity" is almost always what
users want, as it supports the mathematical operations of quantity
calculus. Temperatures, though, are *very* different: in practice, we
often want "quantity point" (maybe even most of the time!).
I think the bar to meet here is that any code that users will naturally
tend to write should not silently produce incorrect results. How to do
that here? We *could* say "make quantity point the default for
temperature", but I think a better approach is "avoid *having* a default
for temperature". Here's how Au does this: users can write
`celsius_qty(20)` to get a *quantity* of 20 degrees Celsius, or
`celsius_pt` to get a *quantity point* representing a temperature of 20
degrees Celsius. If users write `celsius(20)`, this is defined, *but is
marked as `[[deprecated]]` with an error message that directs them to
`celsius_qty` and `celsius_pt`*, making them aware of the problem, and
telling them what solutions are available. See source code:
https://github.com/aurora-opensource/au/blob/221d8f41c41419bbdb585fb4cdea1217b8011fd1/au/units/celsius.hh#L37-L42
I think the idea of adding a "permanently deprecated" member to the
standard library, purely so that users can get a useful error message if
they try to use it, would be a very hard sell, and I'm not proposing it.
But I definitely think we need to avoid code that silently produces grossly
incorrect answers when used in the natural way. Maybe others can think of
a more palatable way to make users aware of the difficulty if they naively
try to do the wrong thing? Or maybe it's enough to simply omit the
"unadorned" names for temperatures.
By the way: as to the specific code example provided, the error is clearly
in the `28.0 * deg_C` expression. As others have pointed out, the
multiplicative syntax *necessarily* only works for quantity, never for
quantity point. Au also has "unit symbol" constructs that behave similarly
to the example. The way we handle it is to, again, omit the unadorned
name. Our unit symbol for degrees Celsius is `deg_C_qty`, putting its
nature front and center, and (I hope) suggesting to the end user that they
should understand why this symbol looks different from all the others.
On Tue, Jun 18, 2024 at 11:43 AM Ville Voutilainen via Std-Proposals <
std-proposals_at_[hidden]> wrote:
> On Tue, 18 Jun 2024 at 18:38, Mateusz Pusz via Std-Proposals
> <std-proposals_at_[hidden]> wrote:
> >
> > Multiply syntax will always create a quantity. So if I write:
> >
> > auto q = 4 * deg_C;
> >
> > I will end up with a delta temperature equal to 4 K.
> >
> > quantity q = 4 * deg_C; // the same thing as above
> >
> > If I try:
> >
> > quantity_point qp = 4 * deg_C;
> >
> > I will get a compile-time error as a quantity_point is not implicitly
> constructible from the quantity.
> >
> > To create a quantity_point, I have to do one of the following:
> >
> > quantity_point qp1 = zeroth_degree_Celsius + 4 * deg_C;
> > quantity_point qp2(4 * deg_C, zeroth_degree_Celsius);
> > quantity_point qp3(4 * deg_C); // proper point origin provided by
> default
> >
> > All of the above will create a temperature point with a value equal to
> 277.15 K.
>
> ..and chrono allows creating objects of such types with a literal,
> whereas this library doesn't?
> --
> Std-Proposals mailing list
> Std-Proposals_at_[hidden]
> https://lists.isocpp.org/mailman/listinfo.cgi/std-proposals
>
Received on 2024-06-18 16:49:46