Files
mp-units/docs/tutorials/tutorial_1.md
2025-10-17 10:45:04 +02:00

97 lines
2.7 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
# Tutorial 1: Refactor to Strong Types
In this tutorial, youll refactor a small legacy function that uses raw doubles into a
typesafe version using **mp-units**. The goal is to accept and return strong, unitaware
types to prevent dimensional bugs at compile time.
## Problem statement
The legacy function computes _kinetic energy_ ($E = \tfrac{1}{2}\, m\, v^2$) and assumes
kilogram and metre per second, but nothing enforces this:
```cpp
double kinetic_energy_j(double mass_kg, double speed_mps)
{
return 0.5 * mass_kg * speed_mps * speed_mps; // Joules (if inputs are indeed kg and m/s)
}
```
## Your task
Refactor the legacy function, and arguments passed to it from `main()` to use strongly
typed quantities (e.g., quantity of mass in kilograms, quantity of speed in metre
per second). Print the result in J and kJ.
When you are done, make a few intentional mistakes and check error messages.
```cpp
// ce-embed height=650 compiler=clang2110 flags="-std=c++23 -stdlib=libc++ -O3" mp-units=trunk
#include <mp-units/systems/si.h>
#include <mp-units/core.h>
#include <iostream>
using namespace mp_units;
using namespace mp_units::si::unit_symbols;
// Legacy implementation
constexpr double kinetic_energy_j(double mass_kg, double speed_mps)
{
return 0.5 * mass_kg * speed_mps * speed_mps;
}
// TODO: Implement a strongly typed version
// ...
int main()
{
double mass_kg = 80;
double speed_mps = 12.5;
auto energy_J = kinetic_energy_j(mass_kg, speed_mps);
std::cout << energy_J << " J (" << energy_J / 1000 << " kJ)\n";
// do the same as above with strong types
//
}
```
??? "Solution"
```cpp
#include <mp-units/systems/si.h>
#include <mp-units/core.h>
#include <iostream>
using namespace mp_units;
using namespace mp_units::si::unit_symbols;
constexpr quantity<si::joule> kinetic_energy(quantity<si::kilogram> mass,
quantity<si::metre / si::second> speed)
{
return 0.5 * mass * pow<2>(speed);
}
int main()
{
quantity mass = 80 * kg;
quantity speed = 12.5 * (m / s);
quantity energy = kinetic_energy(mass, speed);
std::cout << energy << " (" << energy.in(kJ) << ")\n";
}
```
## References
- [Getting Started: Quick Start](../getting_started/quick_start.md)
- [API Reference](../api_reference.md)
## Takeaways
- Function contracts are now selfdocumenting and enforced by the type system.
- Wrongunit calls fail at compile time, preventing latent bugs.
- The return type
- communicates its physical meaning, not just a raw number,
- ensures that the object returned from a function is the result of correct quantity arithmetic.