Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Boost::Tuples vs Structs for return values

I'm trying to get my head around tuples (thanks @litb), and the common suggestion for their use is for functions returning > 1 value.

This is something that I'd normally use a struct for , and I can't understand the advantages to tuples in this case - it seems an error-prone approach for the terminally lazy.

Borrowing an example, I'd use this

struct divide_result {     int quotient;     int remainder; }; 

Using a tuple, you'd have

typedef boost::tuple<int, int> divide_result; 

But without reading the code of the function you're calling (or the comments, if you're dumb enough to trust them) you have no idea which int is quotient and vice-versa. It seems rather like...

struct divide_result {     int results[2]; // 0 is quotient, 1 is remainder, I think }; 

...which wouldn't fill me with confidence.

So, what are the advantages of tuples over structs that compensate for the ambiguity?

like image 443
Roddy Avatar asked Jan 03 '09 20:01

Roddy


People also ask

When would you use a tuple instead of a struct?

So, use tuples when you want to return two or more arbitrary pieces of values from a function, but prefer structs when you have some fixed data you want to send or receive multiple times.

Are tuples structs?

Since tuples are structs there is no much point in making them immutable. The readonliness of a struct is a property of the whole variable. If a tuple variable is assignable, it can be changed to contain any value regardless of the readonliness of individual fields.


2 Answers

tuples

I think i agree with you that the issue with what position corresponds to what variable can introduce confusion. But i think there are two sides. One is the call-side and the other is the callee-side:

int remainder;  int quotient; tie(quotient, remainder) = div(10, 3); 

I think it's crystal clear what we got, but it can become confusing if you have to return more values at once. Once the caller's programmer has looked up the documentation of div, he will know what position is what, and can write effective code. As a rule of thumb, i would say not to return more than 4 values at once. For anything beyond, prefer a struct.

output parameters

Output parameters can be used too, of course:

int remainder;  int quotient; div(10, 3, &quotient, &remainder); 

Now i think that illustrates how tuples are better than output parameters. We have mixed the input of div with its output, while not gaining any advantage. Worse, we leave the reader of that code in doubt on what could be the actual return value of div be. There are wonderful examples when output parameters are useful. In my opinion, you should use them only when you've got no other way, because the return value is already taken and can't be changed to either a tuple or struct. operator>> is a good example on where you use output parameters, because the return value is already reserved for the stream, so you can chain operator>> calls. If you've not to do with operators, and the context is not crystal clear, i recommend you to use pointers, to signal at the call side that the object is actually used as an output parameter, in addition to comments where appropriate.

returning a struct

The third option is to use a struct:

div_result d = div(10, 3); 

I think that definitely wins the award for clearness. But note you have still to access the result within that struct, and the result is not "laid bare" on the table, as it was the case for the output parameters and the tuple used with tie.

I think a major point these days is to make everything as generic as possible. So, say you have got a function that can print out tuples. You can just do

cout << div(10, 3); 

And have your result displayed. I think that tuples, on the other side, clearly win for their versatile nature. Doing that with div_result, you need to overload operator<<, or need to output each member separately.

like image 114
Johannes Schaub - litb Avatar answered Oct 06 '22 20:10

Johannes Schaub - litb


Another option is to use a Boost Fusion map (code untested):

struct quotient; struct remainder;  using boost::fusion::map; using boost::fusion::pair;  typedef map<     pair< quotient, int >,     pair< remainder, int > > div_result; 

You can access the results relatively intuitively:

using boost::fusion::at_key;  res = div(x, y); int q = at_key<quotient>(res); int r = at_key<remainder>(res); 

There are other advantages too, such as the ability to iterate over the fields of the map, etc etc. See the doco for more information.

like image 42
Alastair Avatar answered Oct 06 '22 21:10

Alastair