Tuple abuse
2021-11-03 Permalink
Tuple types tend to be heavily misused. The anonymity of their heterogeneous members obfuscates the code in places where a simple struct
with named fields would be more appropriate.
Let’s walk through a few examples from the C++ standard library and elsewhere (though the discussion is not limited to C++, as I’ve seen Go, Lua and Python code abusing them just as well).
Associative containers (like
std::map
) define theirvalue_type
as:[1]typedef std::pair<const Key, T> value_type;
The key and value of an element of the container are thus given the uninformative names
first
andsecond
. Using astruct
in this context would improve the readability:[2]struct value_type { const Key key; T value; };
- Unique associative containers also have this insert function:
std::pair<iterator,bool> insert(const value_type &value);
15 years in, and I still don’t remember which one is
first
and which one issecond
; nor if thatbool
indicates success or failure. This is another case where a littlestruct
would make a huge difference:struct insert_result_type { iterator where; bool inserted; }; insert_result_type insert(const value_type &value);
equal_range
of all kinds returns apair
:std::pair<Iter,Iter> equal_range(...);
Instead it should have returned an
iterator_range
:template<class Iter> struct iterator_range { Iter first, last; Iter begin() const { return first; } Iter end() const { return last; } // ... };
- Some code uses
tuples
for no justification other than the laziness of the programmer:std::tuple<int,double,double> stats();
Is that a count, mean and variance? Or a count, a minimum and a maximum? Or...?
Just like function parameters have names, so should their return types, or any other aggregate types for that matter. I thus conclude that given a choice between a struct
and a tuple
, the former should be preferred in the vast majority of circumstances.
Tuples are, in their essence, structs
with unnamed fields. In a Fantasy Language™ these two would be conflated.
Footnotes
std::pair
in C++ is an old special case of anstd::tuple
, thus the discussion here applies to it just as well.Perhaps
value
should be renamed tomapped
. However I’d say thatset
andmap
should have been combined by removing thevalue
part altogether, and extracting a key from a user providedvalue_type
.