C++ Strong Type Use-Cases

This is the second instalment of an aptly named “c++ strong duck” post. (a title is an act of deliberate sarcasm vs ‘duck typing’ ). If you haven’t before please make a slight detour to that post, for a brief introduction on strong types. Perhaps an antidote to “type punning“.

The Why

Consider this real-life code

One can mix up values when calling this function in more than one way, on more than one occasion. And, equally bad, if that mistake is made it is extremely hard to catch it. This is the whole point of using strong types. One simply can not make a mistake, that easy as without them.

I just thought to make a little post about the use-case scenarios of this strong type paradigm shift.

For me, the core benefits are simplicity and applicability to both C and C++. And, I indeed might be so bold to think, I can show a few, perhaps surprisingly effective, examples.

Let’s dive

I see nothing wrong with using macros in this instance. Here is the core single macro. Please rename it if it clashes with something in your development environment.

That creates the strong type, a simple struct with the required type name and with the member v of the required value_type. C and C++ dichotomy accounted for from the start.

Whenever necessary, I will notify of the language of the snippet: C or C++.

First classical use case: strong types as physical “units”. One of the oldest general confusions in programming at large. We want units to be distinctive “strong” types, not intrinsic (native) types, where only values are named appropriately.

There are also numerous examples where people have been inventing and coding quite complex unit types, as large C++ classes. I do not do that. Here is how we generate a few declarations of strong types, representing various units.

That’s about it. It is as simple as that. Above we have eight strong types. They all have a name and value_type. They are all structs. Extremely simple structs. Although it is debatable if structs can be simple in C++.

Do not lose the fact, about the simplicity of the code generated above. I have not seen a simpler implementation of the concept of the strong type. But that is not all in the goodie bag. There is more.

Strong types are literals

The above “unit” Meter is literal. That is C++ context.

The Use

We can already code rather safe and simple transformations of linear units, aka lengths. For example.

Above we follow the C++ “pass by value” mandate. Thus we can pass temporaries, and we need no constant arguments. Above can be all used at compile-time, too.

Also, note how these overloads will never confuse the compiler, and in turn, the compiler will never confuse you. One quality, I am sure you being a C++ aficionado, came to appreciate very much.

The usage.

Non allowed transformations simply do not compile. Can the above be made with overloaded function templates? It can. But much more difficult to do it right. And the end result will be just the same. And it will take much longer to develop.

Let us talk a bit more about

Nested strong types

Strong types are indeed useful as class members. In which case they are nested strong types.

That is indeed simple and it works smoothly as long as fundamental types are used for value types of nested types. Otherwise, things will go very complex very quickly.

(Note: in this post, I am using C++20 “designated initializers“. They are already working in all three main compilers.) So, let’s nest the above into the Point struct.

That code requires focus, but it is not that hard. To reach the actual X and Y values, on Point p1, one must type:

Not exactly simple or trivial. So, please stick to single level nesting. It is equally effective.

The above declaration is useful and allows for simple, elegant and safe code. No deep nesting necessary. The key point is: one can not make the easy mistake of mixing x and y. They are strong types, not intrinsic arithmetic types.

Complex nested strong types

Often times, we have complex scenarios and we simply can not evade nesting complex strong types as class members. With a bit of thinking, we can solve that issue too.

Let us assume we want to add some colour to our Duffy, the strong duck from the fist post on strong types.

Colour is a combination of red, green and blue components. And their components are expressed as hex values. Let’s generate the required code for this design.

With the method mix() above we have solved the complexity required by users actually wishing to use the Color instances. Here is the Duck type improved.

That is one non-trivial structure layout. Using the above here is how we create duffy but this time, with some colour, added.

That even looks simple and logical. Now let’s see the usability.

Not trivial but simple. And to actually use the colour we do

Which type is std::array<Hex,3>.

I certainly will use this in the production code. I hope you have seen some value in this simple concept for your projects too.

Exact types of Fasteners
Sub-types of Fasteners type. They are sub-types but it is impossible to confuse them with each other.