128

Why does nobody seem to use tuples in C++, either the Boost Tuple Library or the standard library for TR1? I have read a lot of C++ code, and very rarely do I see the use of tuples, but I often see lots of places where tuples would solve many problems (usually returning multiple values from functions).

Tuples allow you to do all kinds of cool things like this:

tie(a,b) = make_tuple(b,a); //swap a and b

That is certainly better than this:

temp=a;
a=b;
b=temp;

Of course you could always do this:

swap(a,b);

But what if you want to rotate three values? You can do this with tuples:

tie(a,b,c) = make_tuple(b,c,a);

Tuples also make it much easier to return multiple variable from a function, which is probably a much more common case than swapping values. Using references to return values is certainly not very elegant.

Are there any big drawbacks to tuples that I'm not thinking of? If not, why are they rarely used? Are they slower? Or is it just that people are not used to them? Is it a good idea to use tuples?

Zifre
  • 26,504
  • 11
  • 85
  • 105
  • 11
    `a = a ^ b; b = a ^ b; a = a ^ b;` – Gerardo Marset Sep 27 '11 at 23:59
  • 3
    IMO tuples are convenient in weak typing languages or languages in which they are native structures. For example in Python or PHP they just make life easier, while in C++ there is too much typing (to construct it from template) and too few benefits. – mip Jan 26 '13 at 20:06
  • 4
    A comment to the OP: I think that the current accepted answer is already obsoleted to the point of being factually wrong. You may want to reconsider the choice of the accepted answer. – ulidtko Sep 30 '14 at 08:30
  • 9
    @GerardoMarset Are you serious? – thesaint Jun 20 '15 at 07:51
  • 1
    @Zifre "Tuples also make it much easier to return multiple variable from a function" Sorry, but std::pair is already far fetched, but returning an std::tuple in normal production code is a death sin. Those are the days where I wish I had a "delete pull request" in our companies review board. I recommend a book like "clean code", instead of using boost::tuple ;). – thesaint Jun 20 '15 at 07:52
  • 1
    @ulidtko The question aged with its accepted answer. The fact that `tuple` is now standard may have had a positive impact on its frequency of use. – P-Gn Sep 24 '15 at 15:11
  • 1
    The swap trick doesn't justify tuples. You can use a variadic rotate fn for that. – QuentinUK May 10 '16 at 10:55

12 Answers12

126

A cynical answer is that many people program in C++, but do not understand and/or use the higher level functionality. Sometimes it is because they are not allowed, but many simply do not try (or even understand).

As a non-boost example: how many folks use functionality found in <algorithm>?

In other words, many C++ programmers are simply C programmers using C++ compilers, and perhaps std::vector and std::list. That is one reason why the use of boost::tuple is not more common.

Trey Jackson
  • 73,529
  • 11
  • 197
  • 229
  • 28
    -1 from me because C++ programmers aren't as dumb as this answer makes them sound. – user541686 Mar 22 '14 at 02:30
  • 6
    @Mehrdad Having looked through a lot of C++ code, both commercial and not, reading tons of C++ material, I think it's fairly safe to say that a very large portion of "C++" developers are just C developers who couldn't get a pure C compiler. Templates, for example, are almost entirely missing from most materials (something I've learned to love a lot). Strange macro hacks are common and namespace are severely underused. – Clearer Oct 05 '14 at 15:10
  • 6
    Nonsense answer. If one does need them, they will catch up with them. They are not needed; so they are not used. Saying that they are not used because they are not easily understood is bad. – Michael Chourdakis Nov 12 '14 at 19:17
  • 10
    @Michael Nonsense comment. Nothing is *needed* in programming once you've got a Turing complete subset of a language. Lack of use certainly doesn't imply that everyone understands the higher level C++ constructs and chooses to not use them. – Trey Jackson Nov 17 '14 at 16:09
  • 1
    @TreyJackson Agreed, but std::tuple is terribly UNHANDY (I don't know about boost::tuple). It's a pain to work with it. I suppose that's why its not used. I used it for variadic template metaprogramming and causing proper runtime effects, but that's not a use-case as I would call :D. And I am one of those who could simply write a tuple if it wasn't there. The fact that you need template lambdas (aka template structs with call operator) and proper type-algorithms to work with them makes them neither maintainable nor user friendly. But indispensible for variadic programming. – thesaint Jun 20 '15 at 07:42
  • 5
    Tbh I NEVER ever had the need for std::tuple outside of variadic template metaprogramming. There was no point in life where I sat down with a sad face thinking "If only I had those tuples". In fact when I look at tuples I think "What the hell would someone sane need them for (I wouldn't consider myself sane)". People outside of meta-programming seems to use them as "Anonymous Struct" which is so ugly and indicates a strong absence of code quality and maintainability in their heads. – thesaint Jun 20 '15 at 07:47
  • @thesaint No argument with your comments. My answer is just one possibility of why they aren't used and isn't arguing that `std::tuple` is actually useful. If you understand `boost` or you use more of C++ than the bare minimum, then this answer obviously doesn't apply to you. – Trey Jackson Nov 30 '15 at 16:57
  • 1
    This is a wretched answer. You didn't actually explain _why_ people should be using `std::tuple` and aren't - under what conditions we should be using it. And in fact, in almost all cases, a struct with named fields is the right choice - it's self-documenting and always at least as efficient as a tuple and in some cases more. – Tom Swirly Jul 08 '16 at 20:20
  • 1
    @TomSwirly The question wasn't "why should people use tuple?" It was "why *aren't* people using tuple?" Did you not understand the question? – Trey Jackson Jul 27 '16 at 16:54
  • 1
    I'm inclined to agree with @TomSwirly, though "wretched" might be a bit far. You're basically saying 'tuples aren't used much because all those people aren't real C++ programmers': `do not understand and/or use the higher level functionality`. That probably has some general validity - but here, specifically, it conveys an implicit message... there is some reason to use tuples, as they are "higher level", but darn C programmers aren't clever enough to get it. It's perfectly justified for Tom to ask you for cases in which it would be better to use tuples, vs doing whatever said users do instead. – underscore_d Oct 09 '16 at 13:49
  • 1
    @underscore_d So... the answer may have some validity, but I should change it. The question was, "Why is the use of tuples in C++ not more common?" And I answered that. If you want justification for why people should use it, ask THAT question. It's ridiculous to chastise me for not answering a question not asked. AGAIN, I'm not arguing that people SHOULD use tuple (I don't us it), I'm providing one possible reason they don't. Note: You are adding the judgement of C programmers not being "clever enough". My wife doesn't understand tuple, it has no relationship to her intelligence. – Trey Jackson Oct 11 '16 at 15:30
  • The claim of this answer is supported by all the answers that state that tuples are not useful. I really could not believe what people in this thread are claiming. Most certainly they have never before programmed in a language that makes (heavy) use of tuples. You – ziggystar Feb 21 '18 at 08:24
43

Because it's not yet standard. Anything non-standard has a much higher hurdle. Pieces of Boost have become popular because programmers were clamoring for them. (hash_map leaps to mind). But while tuple is handy, it's not such an overwhelming and clear win that people bother with it.

Alan De Smet
  • 1,699
  • 1
  • 16
  • 20
  • 1
    People seem to use other parts of Boost like crazy. Although certainly hash maps are much more useful in general than tuples. – Zifre May 12 '09 at 22:13
  • I don't know the specifics of what you're seeing, but I'm guessing that the parts people are using like crazy are features they really, really wanted. Thus (again, guessing) the popularity of the hash map, the counted pointer, and the like. The tuple is handy, but it's not something that leaps out to fill a hole. The payoff isn't obvious. How often do you need to rotate exactly N objects? (As opposed to needing to rotate arbitrarily long vectors). And people are used to either passing return values in by reference, or returning small classes or structs. – Alan De Smet May 18 '09 at 21:16
  • 21
    It's actualy a part of C++11 standard now: http://en.cppreference.com/w/cpp/utility/tuple – Roman Susi Oct 12 '13 at 06:05
24

The C++ tuple syntax can be quite a bit more verbose than most people would like.

Consider:

typedef boost::tuple<MyClass1,MyClass2,MyClass3> MyTuple;

So if you want to make extensive use of tuples you either get tuple typedefs everywhere or you get annoyingly long type names everywhere. I like tuples. I use them when necessary. But it's usually limited to a couple of situations, like an N-element index or when using multimaps to tie the range iterator pairs. And it's usually in a very limited scope.

It's all very ugly and hacky looking when compared to something like Haskell or Python. When C++0x gets here and we get the 'auto' keyword tuples will begin to look a lot more attractive.

The usefulness of tuples is inversely proportional to the number of keystrokes required to declare, pack, and unpack them.

user21714
  • 5,781
  • 1
  • 20
  • 26
  • Most people will do "using namespace boost;" and not have to type boost::. I don't think typing tuple is that much of a problem. That said, I think you have a point. auto might make a lot more people start using tuples. – Zifre May 12 '09 at 23:23
  • 2
    @Zifre: the problem is that you shouldn't do "using namespace X" within a header file because it forces namespace pollution and subverts the namespaces. – Mr Fooz May 13 '09 at 00:47
  • 1
    Ah, yes, I forget about headers. But inside program code, you don't need to worry about it. And once we have C++0x, we can use auto which should eliminate a lot of the typing. – Zifre May 14 '09 at 20:12
  • 19
    Is it just me? I don't think saving typing the 7 characters of "boost::" is what he was referring to, but rather the *other 33 characters*. That's a heck of a lot of classname typing, especially if those, too are namespace scoped. Take boost::tuple,std::vector > as a ridiculous example. – Ogre Psalm33 Jun 14 '11 at 20:06
10

For me, it's habit, hands down: Tuples don't solve any new problems for me, just a few I can already handle just fine. Swapping values still feels easier the old fashioned way -- and, more importantly, I don't really think about how to swap "better." It's good enough as-is.

Personally, I don't think tuples are a great solution to returning multiple values -- sounds like a job for structs.

ojrac
  • 13,231
  • 6
  • 37
  • 39
  • 4
    'I don't really think about how to swap "better."' - When I write code, I write bugs. Reducing code complexity reduces the number of bugs I write. I hate to create the same bugs again and again. **Yes, I do think about how to swap> code better**. Fewer moving parts (LOC, temp variables, identifiers to mistype), more readable code; Good Code. – sehe Sep 23 '11 at 08:22
  • Agree. A class wrapped in auto-pointer or a smart pointer is type-save. I've used tuples once, but then rewritten the code using classes. retValue.state is more clear than retValue.get<0>(). – Valentin H May 06 '14 at 07:48
  • 1
    @sehe: Writing better, more readable code is my goal as well. Adding more types of syntax has a cost, and I don't believe "better swapping" justifies the mental overhead of thinking about even more types of syntax for every line of code you read. – ojrac May 29 '14 at 15:32
8

As many people pointed out, tuples are just not that useful as other features.

  1. The swapping and rotating gimmicks are just gimmicks. They are utterly confusing to those who have not seen them before, and since it is pretty much everyone, these gimmicks are just poor software engineering practice.

  2. Returning multiple values using tuples is much less self-documenting then the alternatives -- returning named types or using named references. Without this self-documenting, it is easy to confuse the order of the returned values, if they are mutually convertible, and not be any wiser.

igorlord
  • 376
  • 3
  • 4
8

But what if you want to rotate three values?

swap(a,b);
swap(b,c);  // I knew those permutation theory lectures would come in handy.

OK, so with 4 etc values, eventually the n-tuple becomes less code than n-1 swaps. And with default swap this does 6 assignments instead of the 4 you'd have if you implemented a three-cycle template yourself, although I'd hope the compiler would solve that for simple types.

You can come up with scenarios where swaps are unwieldy or inappropriate, for example:

tie(a,b,c) = make_tuple(b*c,a*c,a*b);

is a bit awkward to unpack.

Point is, though, there are known ways of dealing with the most common situations that tuples are good for, and hence no great urgency to take up tuples. If nothing else, I'm not confident that:

tie(a,b,c) = make_tuple(b,c,a);

doesn't do 6 copies, making it utterly unsuitable for some types (collections being the most obvious). Feel free to persuade me that tuples are a good idea for "large" types, by saying this ain't so :-)

For returning multiple values, tuples are perfect if the values are of incompatible types, but some folks don't like them if it's possible for the caller to get them in the wrong order. Some folks don't like multiple return values at all, and don't want to encourage their use by making them easier. Some folks just prefer named structures for in and out parameters, and probably couldn't be persuaded with a baseball bat to use tuples. No accounting for taste.

Steve Jessop
  • 273,490
  • 39
  • 460
  • 699
  • 1
    You definitely wouldn't want to swap vectors with tuples. I think swapping three elements is certainly more clear with tuples than with two swaps. As for multiple return values, out parameters are evil, structs are extra typing, and there definitely are cases where multiple return values are needed. – Zifre May 13 '09 at 00:24
  • know why *you* use tuples (and I know why I'd use them if the occasion arose, although I don't think it ever has). I'm guessing why other people don't use them even if they're aware of them. e.g. because they disagree with "out params are evil"... – Steve Jessop May 13 '09 at 00:33
  • Do you know if we can replace "tie(a,b,c) = make_tuple(b,c,a);" by "tie(a,b,c) = tie(b,c,a);" ? – Rexxar May 13 '09 at 01:53
  • @Rexxar: I was wondering that too. It's less typing, and my tests show that it works, but I have a feeling it's not correct. I would appreciate it if somebody could answer this question. – Zifre May 13 '09 at 22:06
  • 2
    A tie (well, a tier technically) is a tuple made with non-const references. I can't find boost documentation which says what guarantees operator= and the copy constructor for tie/tuple make when some of the references involved have the same referand. But that's what you need to know. A naive implementation of operator= clearly could go very wrong... – Steve Jessop May 15 '09 at 11:38
  • 1
    @Steve: And since ties are all about preventing copies (they should work for non-copyable types; note that the LHS might be something else entirely) indeed it all _should_ go very wrong (think of non-POD class objects). Just imagine how you'd write the same logic without using temps. – sehe Sep 23 '11 at 08:31
  • Doing permutations as swaps could be made more clear by putting a note in the comments containing the equivalent cycle notation. Or is cycle notation not widely known in the CS community? – Tim Seguine Sep 30 '13 at 10:39
  • @Tim: personally I wouldn't count on it being understood. Writing `(a c b)` as the comment to `swap(a,b); swap(b,c)` instead of "rotate three values" just seems to be asking for trouble to me, even though it is less ambiguous to those who understand the notation. A compromise could probably be found though, such as writing `a -> c -> b -> a`. – Steve Jessop Sep 30 '13 at 18:25
  • I was thinking more of the generalization to larger permutations, but your point is well taken. – Tim Seguine Sep 30 '13 at 19:59
6

Not everyone can use boost, and TR1 isn't widely available yet.

Brian Neal
  • 31,821
  • 7
  • 55
  • 59
  • 4
    A lot of people use Boost. Those people could be using tuples also. – Zifre May 12 '09 at 23:54
  • 3
    You asked why people don't use them, and I gave one answer. – Brian Neal May 13 '09 at 15:03
  • 2
    To the down voter: I happen to work in a place where it is politically impossible to use boost, and even at this date, the compiler tool chain we use (for an embedded system) does not have TR1 / C++11 support. – Brian Neal Mar 26 '12 at 20:28
5

You rarely see them because well-designed code usually doesn't need them- there are not to many cases in the wild where using an anonymous struct is superior to using a named one. Since all a tuple really represents is an anonymous struct, most coders in most situations just go with the real thing.

Say we have a function "f" where a tuple return might make sense. As a general rule, such functions are usually complicated enough that they can fail.

If "f" CAN fail, you need a status return- after all, you don't want callers to have to inspect every parameter to detect failure. "f" probably fits into the pattern:

struct ReturnInts ( int y,z; }
bool f(int x, ReturnInts& vals);

int x = 0;
ReturnInts vals;
if(!f(x, vals)) {
    ..report error..
    ..error handling/return...
}

That isn't pretty, but look at how ugly the alternative is. Note that I still need a status value, but the code is no more readable and not shorter. It is probably slower too, since I incur the cost of 1 copy with the tuple.

std::tuple<int, int, bool> f(int x);
int x = 0;
std::tuple<int, int, bool> result = f(x); // or "auto result = f(x)"
if(!result.get<2>()) {
    ... report error, error handling ...
}

Another, significant downside is hidden in here- with "ReturnInts" I can add alter "f"'s return by modifying "ReturnInts" WITHOUT ALTERING "f"'s INTERFACE. The tuple solution does not offer that critical feature, which makes it the inferior answer for any library code.

Zack Yezek
  • 1,408
  • 20
  • 7
  • 1
    Exceptions make that interface much cleaner. – David Stone Mar 30 '13 at 01:43
  • To be fair (and extremely late to the party) you could ease readability by setting ``using std::tuple;`` and just use ``tuple`` in the code. – Alrekr Jun 11 '15 at 17:25
  • 2
    Using `tuple` makes the code _less_ readable, not more. Most code these days has a very large number of symbols in it - seeing `std::tuple` makes it clear to the eye exactly what it is. – Tom Swirly Jul 08 '16 at 20:18
5

When using C++ on embedded systems, pulling in Boost libraries gets complex. They couple to each other, so library size grows. You return data structures or use parameter passing instead of tuples. When returning tuples in Python the data structure is in the order and type of the returned values its just not explicit.

DanM
  • 2,331
  • 2
  • 18
  • 14
3

Certainly tuples can be useful, but as mentioned there's a bit of overhead and a hurdle or two you have to jump through before you can even really use them.

If your program consistently finds places where you need to return multiple values or swap several values, it might be worth it to go the tuple route, but otherwise sometimes it's just easier to do things the classic way.

Generally speaking, not everyone already has Boost installed, and I certainly wouldn't go through the hassle of downloading it and configuring my include directories to work with it just for its tuple facilities. I think you'll find that people already using Boost are more likely to find tuple uses in their programs than non-Boost users, and migrants from other languages (Python comes to mind) are more likely to simply be upset about the lack of tuples in C++ than to explore methods of adding tuple support.

Zac
  • 876
  • 1
  • 8
  • 18
1

As a data-store std::tuple has the worst characteristics of both a struct and an array; all access is nth position based but one cannot iterate through a tuple using a for loop.

So if the elements in the tuple are conceptually an array, I will use an array and if the elements are not conceptually an array, a struct (which has named elements) is more maintainable. ( a.lastname is more explanatory than std::get<1>(a)).

This leaves the transformation mentioned by the OP as the only viable usecase for tuples.

doron
  • 27,972
  • 12
  • 65
  • 103
0

I have a feeling that many use Boost.Any and Boost.Variant (with some engineering) instead of Boost.Tuple.

dirkgently
  • 108,024
  • 16
  • 131
  • 187