diff --git a/docs/blog/posts/2.2.0-released.md b/docs/blog/posts/2.2.0-released.md new file mode 100644 index 000000000..26cfa43fa --- /dev/null +++ b/docs/blog/posts/2.2.0-released.md @@ -0,0 +1,299 @@ +--- +draft: true +date: 2024-01-09 +authors: + - mpusz +categories: + - Releases +--- + +# mp-units 2.2.0 released! + +**A new product version can be obtained from +[GitHub](https://github.com/mpusz/mp-units/releases/tag/v2.2.0) and +[Conan](https://conan.io/center/recipes/mp-units?version=2.2.0).** + +Among other features, this release provides long-awaited support for C++20 modules, redesigns text +output formatting, and greatly simplifies quantity point usage. This post describes those and a few +other smaller interesting improvements, while a list of the most significant changes introduced by +the new version can be found in our [Release Notes](../../release_notes.md#2.2.0). + + + +## C++20 modules + +[GitHub Issue #7](https://github.com/mpusz/mp-units/issues/7) was our oldest open issue +before this release. Not anymore. After 4.5 years, we finally closed it, even though +the C++ modules' support is still really limited. + +!!! info + + To benefit from C++ modules, we need at least: + + - CMake 3.28.1 + - Ninja 1.11 + - clang-17 + +In the upcoming months, hopefully the situation will improve with the gcc-14 release and +bug fixes in MSVC. + +!!! note + + More requirements for C++ modules support can be found in the + [CMake's documentation](https://cmake.org/cmake/help/latest/manual/cmake-cxxmodules.7.html). + +To enable the compilation and distribution of C++ modules, a +[`cxx_modules`](../../getting_started/installation_and_usage.md#cxx_modules) Conan or +[`MP_UNITS_BUILD_CXX_MODULES`](../../getting_started/installation_and_usage.md#MP_UNITS_BUILD_CXX_MODULES) +CMake option has to be enabled. + +With the above, the following C++ modules will be provided: + +```mermaid +flowchart TD + mp_units --- mp_units.systems --- mp_units.core +``` + +| C++ Module | CMake Target | Contents | +|--------------------|----------------------|----------------------------------------------------------| +| `mp_units.core` | `mp-units::core` | Core library framework and systems-independent utilities | +| `mp_units.systems` | `mp-units::systems` | All the systems of quantities and units | +| `mp_units` | `mp-units::mp-units` | Core + Systems | + +The easiest way to use them is just to `import mp_units;` at the beginning of your translation unit +(see the [Quick Start](../../getting_started/quick_start.md) chapter for some usage examples). + +In this release, we also highly limited the number of CMake targets (**breaking change**). Now, they +correspond exactly to the C++ modules they provide. This means that many smaller partial targets +were removed. We also merged text output targets with the core library's definition. + +The table below specifies where we can find now the contents of previously available CMake targets: + +| Before | Now | +|---------------------------|---------------------| +| `mp-units::utility` | `mp-units::core` | +| `mp-units::core-io` | `mp-units::core` | +| `mp-units::core-fmt` | `mp-units::core` | +| `mp-units::{system_name}` | `mp-units::systems` | + +While we were enabling C++ modules, we also had to refactor our header files slightly +(**breaking change**). Some had to be split into smaller pieces (e.g., _math.h_), while +others had to be moved to a different subdirectory (e.g., _chrono.h_). + +In version 2.2, the following headers have a new location or contents: + +| Header File | C++ Module | Contents | +|-----------------------------------|--------------------|-------------------------------------------------| +| _mp-units/math.h_ | `mp_units.core` | System-independent functions only | +| _mp-units/systems/si/math.h_ | `mp_units.systems` | Trigonometric functions using `si::radian` | +| _mp-units/systems/angular/math.h_ | `mp_units.systems` | Trigonometric functions using `angular::radian` | +| _mp-units/systems/si/chrono.h_ | `mp_units.systems` | `std::chrono` compatibility traits | + +Additionally, we merged all of the compatibility-related macros into one header file +_mp-units/compat_macros.h_. This header file should be explicitly included before importing C++ +modules if we want to benefit from the [Wide Compatibility tools](../../users_guide/use_cases/wide_compatibility.md). + + +## Simplified quantity point support + +This release significantly simplifies the usage of quantity points and affine space abstractions +in general. + +Previously, the user always had to define an explicit point origin even if the domain being modeled +does not have such an explicit origin. Now, in such cases, we can benefit from the implicit point +origins. For example: + +=== "Now" + + ```cpp + quantity_point price_usd{100 * USD}; + ``` + +=== "Before" + + ```cpp + constexpr struct zero : absolute_point_origin {} zero; + + quantity_point price_usd = zero + 100 * USD; + ``` + +As we can see above, the new design allows +[direct-initialization](https://en.cppreference.com/w/cpp/language/direct_initialization) of a +`quantity_point` class template from a `quantity`, but only if the former one is defined in terms +of the implicit point origin. Otherwise, an explicit origin still always has to be provided during +initialization. + +Also, we introduced a possibility to specify a default point origin in the units definition. +With that, we could provide proper temperature scales without forcing the user to always use +the origins explicitly. Also, a new member function, `.quantity_from_zero(),` was introduced +that always returns the quantity from the unit's specific point origin or from the absolute +point origin otherwise. + +=== "Now" + + ```cpp + quantity_point temp{20 * deg_C}; + std::cout << "Temperature: " << temp << " (" + << temp.in(deg_F).quantity_from_zero() << ", " + << temp.in(K).quantity_from_zero() << ")\n"; + ``` + +=== "Before" + + ```cpp + quantity_point temp = si::zeroth_degree_Celsius + 20 * deg_C; + std::cout << "Temperature: " << temp << " (" + << temp.in(deg_F).quantity_from(usc::zeroth_degree_Fahrenheit) << ", " + << temp.in(K).quantity_from(si::zeroth_kelvin) << ")\n"; + ``` + +More information about the new design can be found in +[The Affine Space](../../users_guide/framework_basics/the_affine_space.md) +chapter. + + +## Unified temperature point origins names + +By omission, we had the following temperature point origins in the library: + +- `si::zero_kelvin` (for `si::kelvin`), +- `si::zeroth_degree_Celsius` (for `si::degree_Celsius`), +- `usc::zero_Fahrenheit` (for `usc::degree_Fahrenheit`). + +With this release, the last one was renamed to `usc::zeroth_degree_Fahrenheit` to be consistently +named with its corresponding unit and with the `si::zeroth_degree_Celsius` (**breaking change**). + + +## Improved casts + +We added a new conversion function. `value_cast` forces the conversion +of both a unit and representation type in one step and always ensures that the best precision +is provided. + +Also, we have finally added proper implementations of `value_cast` and `quantity_cast` for +quantity points. + + +## Changes to units definitions + +[WG21 Study Group 16 (Unicode) raised concerns](https://github.com/sg16-unicode/sg16-meetings#january-24th-2024) +about potential ABI issues when different translation units are compiled with different ordinary +literal encodings. Those issues were resolved with a change to units definitions (**breaking +change**). It affects only units that specify both Unicode and ASCII symbols. The new design +requires the Unicode symbol to be provided as a UTF-8 literal: + +=== "Now" + + ```cpp + inline constexpr struct ohm : named_unit<{u8"Ω", "ohm"}, volt / ampere> {} ohm; + ``` + +=== "Before" + + ```cpp + inline constexpr struct ohm : named_unit<{"Ω", "ohm"}, volt / ampere> {} ohm; + ``` + + +## Even better error messages + +This release made a few small refactorings that without changing the user-facing API allowed us +to improve the readability of the generated types that can be observed in the compilation errors. + +Example 1 (clang): + +=== "Now" + + ```txt + error: no matching function for call to 'time_to_goal' + 26 | const quantity ttg = time_to_goal(half_marathon_distance, pace); + | ^~~~~~~~~~~~ + note: candidate template ignored: constraints not satisfied [with distance:auto = quantity{}, double>, + speed:auto = quantity>>{}, double>] + 13 | QuantityOf auto time_to_goal(QuantityOf auto distance, + | ^ + note: because 'QuantityOf > >{{{}}}>, isq::speed>' evaluated to false + 14 | QuantityOf auto speed) + | ^ + note: because 'QuantitySpecOf > >{{{}}}, double>::quantity_spec)>, struct speed{{{}}}>' evaluated to false + 61 | concept QuantityOf = Quantity && QuantitySpecOf, QS>; + | ^ + note: because 'implicitly_convertible(kind_of_ > >{}, struct speed{{{}}})' evaluated to false + 147 | QuantitySpec && QuantitySpec> && implicitly_convertible(T{}, QS) && + | ^ + 1 error generated. + Compiler returned: 1 + ``` + +=== "Before" + + ```txt + error: no matching function for call to 'time_to_goal' + 26 | const quantity ttg = time_to_goal(half_marathon_distance, pace); + | ^~~~~~~~~~~~ + note: candidate template ignored: constraints not satisfied [with distance:auto = quantity{}, double>, + speed:auto = quantity>>{}, double>] + 13 | QuantityOf auto time_to_goal(QuantityOf auto distance, + | ^ + note: because 'QuantityOf > >{{{}}}>, isq::speed>' evaluated to false + 14 | QuantityOf auto speed) + | ^ + note: because 'QuantitySpecOf > >{{{}}}, double>::quantity_spec)>, struct speed{{{}}}>' evaluated to false + 61 | concept QuantityOf = Quantity && QuantitySpecOf, QS>; + | ^ + note: because 'implicitly_convertible(kind_of_ >{{}, {{}}}>{}, struct speed{{{}}})' evaluated to false + 147 | QuantitySpec && QuantitySpec> && implicitly_convertible(T{}, QS) && + | ^ + 1 error generated. + Compiler returned: 1 + ``` + +Example 2 (gcc): + +=== "Now" + + ```txt + error: no matching function for call to 'Box::Box(quantity(), int>, quantity(), int>, + quantity(), int>)' + 27 | Box my_box(isq::height(1 * m), horizontal_length(2 * m), isq::width(3 * m)); + | ^ + note: candidate: 'Box::Box(quantity()>, quantity()>, + quantity()>)' + 19 | Box(quantity l, quantity w, quantity h): + | ^~~ + note: no known conversion for argument 1 from 'quantity(),int>' + to 'quantity(),double>' + 19 | Box(quantity l, quantity w, quantity h): + | ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~^ + ``` + +=== "Before" + + ```txt + error: no matching function for call to 'Box::Box(quantity(), int>, quantity(), int>, + quantity(), int>)' + 27 | Box my_box(isq::height(1 * m), horizontal_length(2 * m), isq::width(3 * m)); + | ^ + note: candidate: 'Box::Box(quantity()>, quantity()>, + quantity()>)' + 19 | Box(quantity l, quantity w, quantity h): + | ^~~ + note: no known conversion for argument 1 from 'quantity(),int>' + to 'quantity(),double>' + 19 | Box(quantity l, quantity w, quantity h): + | ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~^ + ``` + + +## _math.h_ header changes + +This release provided lots of changes to the _mp_units/math.h_ header file. + +First, `fma`, `isfinite`, `isinf`, and `isnan` math function were added by +[@NAThompson](https://github.com/NAThompson). Thanks! + +Additionally, we changed the namespace for trigonometric functions using SI units. Now they are +inside of the `mp_units::si` subnamespace and not in `mp_units::isq` like it was the case before +(**breaking change**). + +Also, the header itself was split into smaller pieces that improve C++20 modules definitions.