Skip to content

Units with linear offsets are fundamentally broken (e.g. temperature units) #240

@burnpanck

Description

@burnpanck

The suggested solution to (#75) as implemented is no solution at all. As others have pointed out (e.g. in a comment by @JaapAap), relative and absolute are really not compatible - you cannot have both functionalities in one arithmetic type:

  • Absolute units:
    • do not support arithmetic operations except addition and subtraction of a relative unit
    • convert with application of the linear offset
  • Relative units:
    • do support all common arithmetic operations
    • convert without application of the linear offset

A library will have to decide which of the two it wants to support (e.g. boost supports both through different types), but mixing those two behaviors leads to plain wrong (inconsistent, non-physical and confusing) behavior.
This seems a confusing topic, given that I seem to be having this discussion in every other units library of the programming languages I'm working with. The fundamental benefit of working with units is that it does not matter in which unit operations are performed, i.e. one may first convert, then add, or first add, then convert units. This makes absolute units fundamentally incompatible with most arithmetic operations.

Let me show this using an example, where I prepend r to unit names to indicate relative units, and a to indicate absolute units.

  • Addition of relative units are consistent, such as 5 r°C + 9 r°F: Convert first to Fahrenheit, and you'll find 9 r°F + 9 r°F = 18 r°F. Convert first to Celsius and you'll find 5 r°C + 5 r°C = 10 r°C. Both results are consistent, because 18 r°F = 10 r°C.
  • Addition of absolute units do not make sense: What should 5 a°C + 9 a°F even mean? Convert first to Fahrenheit: 41 a°F + 9 a°F = 50 a°F. Convert first to Celsius: 5 a°C + -4.8 a°C = 0.2 a°C.
    But 50 a°F = 10 a°C, not 0.2 a°C! Even the most naive interpretation of either 14 a°F or 14 a°C would all be inconsistent.
  • Multiplication (e.g. squaring) of relative units is constistent: (10 r°C)² = 100 r°C². Converting this expression to Kelvin, you'll find (10 rK)² = 100 rK².
  • On the other hand, if the squared absolute units a°C² and aK² existed you would find (10 a°C)² = 100 a°C². But since 10 a°C ~ 293 aK, you would also find (293 aK)² = 85849 aK². Whatever conversion function (linear offset or otherwise) your would define to convert 85849 aK² to 100 a°C², you would find it to be inconsistent if you repeat the same for other temperatures.

Because most arithmetic operations make no sense when applied to units that have linear offsets in their conversion rules, I wager to say that most people used this package mostly for conversion when working with temperatures. Otherwise, more issues would have popped up (#75 is one of those - that user really expects relative unit behavior). Therefore, current users implicitly assume absolute unit behavior. The only sane solution without breaking people's expectations is thus to disallow all arithmetic operations on temperatures.

However, since we seem to be at an API-breaking version change (version 3.x upcoming), maybe now would the time be to reconsider? I would consider the library much more useful, if temperature units would support arithmetic too, i.e. represent relative units and do not apply any linear offsets at all. That kind of functionality would be better implemented using an absolute_unit<dimension,...> type such as boost did, because it makes it easy to prevent arithmetic operations (and provide good error messages).

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions