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_typeas:[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
firstandsecond. Using astructin 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
firstand which one issecond; nor if thatboolindicates success or failure. This is another case where a littlestructwould make a huge difference:struct insert_result_type { iterator where; bool inserted; }; insert_result_type insert(const value_type &value); equal_rangeof 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
tuplesfor 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::pairin C++ is an old special case of anstd::tuple, thus the discussion here applies to it just as well.Perhaps
valueshould be renamed tomapped. However I’d say thatsetandmapshould have been combined by removing thevaluepart altogether, and extracting a key from a user providedvalue_type.
