tags:

views:

3676

answers:

9

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?

+16  A: 

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
People seem to use other parts of Boost like crazy. Although certainly hash maps are much more useful in general than tuples.
Zifre
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
A: 

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

dirkgently
Why would you trade efficient static typing for something like those?
Zifre
Boost.Variant is completely type-safe.
Oops, yes it is typesafe, but it does runtime typing.
Zifre
No, Boost.Variant is completely compile time. Boost.Any does runtime typing.
Joe D
@Joe D: I mean in the sense that you can try to get an `int` out of a variant containing a `string`.
Zifre
Also, Any/Variant contain a _single_ value of an unknown (but possible restricted) type. A tuple contains _multiple_ values of known type.
Zifre
+7  A: 

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.

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
@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
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
+2  A: 

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
+2  A: 

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

Brian Neal
A lot of people use Boost. Those people could be using tuples also.
Zifre
You asked why people don't use them, and I gave one answer.
Brian Neal
+14  A: 

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 std::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
+2  A: 

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
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
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
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
@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
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
+4  A: 

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
+1  A: 

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