C++ is, in principle, a strongly typed language. It does, however, allow some implicit conversions between types, making it “not quite as strong as it could be”-typed. Historically, a lot of these implicit conversions come from C — a language which we all agree could use a little less implicit conversions. C++ also doesn’t have a really easy way to add “units” to types, and allows any typedef to be implicitly converted to another.
Before we get to a solution to the issue, we need to understand what the issue is, and why it’s an issue.
To understand what the issue is, consider this example of a “pizza-slice” area calculation, where we want to calculate the area of a segment of a circle:
In this example we will use a circle of radius
r = 5.0 cm and a segment with an angle of
50.86°. The area of the segment then works out to be around
The code for this might look something like this:
Now, this code works, but it has a lot of pitfalls. Is angle in degrees or radians? Is radius in meters, centimeters, feet, …? What if we called it with radius and angle swapped, by accident (since they are both float)?
Now that we have understood the issue, let’s address it.
A common first step would be to add documentation and extend the naming to
angle_in_degrees, maybe even add some
using’s to alias float to different names. And while these are all great, let’s consider using structs to encapsulate our types in the type-system, and thus offloading this work to the compiler:
This adds a lot of code, but not much complexity, and any optimizing compiler will optimize the structs away. But now, when you try passing a length to an angle, you get a compile-time error! The compiler now ensures that you can’t pass an angle to a length argument — and that is very, very powerful.
Now, there are a few issues with this:
You can define all sorts of fancy operators (operator+, operator*), and end up with a massive amount of complexity. I have deliberately not done this, since it defeats the purpose of the “simplicity” of this solution, and is in no way necessary.
Your types are still not perfect. This example doesn’t “check” if you’re passing centimeters to feet, or anything like that, but that can easily be achieved by pushing this concept further with LengthInCm and similar.
You can, however, further expand this to have helpers, for example the Degrees type should probably have a to_radians method, or maybe even an implicit conversion via operator Radians() , and of course assignment operator(s), which I left out for clarity’s sake.