Jeremy said:
You take every example mentioned to date, which is largely:
* OS code trying to be as thin as possible (stat, socket)
* math-type code where the tuple really is the class, as you suggest
* more-or-less contrived one- or two-liner code
and you've still got way, way, way less than 1% of the code of the vast
majority of programs.
Like any other code smell, there are times to use it. But I say it's a
*smell*, and those of you implicitly reading that to mean "Returning
tuples is *never* a good idea" are doing me a disservice; please go look
up "code smell" and the word "generally".
Well, the first page I found that listed the term "code smell" also mentioned
"code wants to be simple", and having scanned through a good sized chunk of
Python code looking to see where multiple return values were used, I am now of
the opinion that, not only are multiple return values _not_ automatically code
smell, but they are one of the key ingredients to avoiding monolithic functions
(and thus they help keep code simple).
The code I looked through had about 4500 return statements. Of those, roughly
350 were returns with multiple values. Of those, 26 had 4 or more return values
- if code smell is a hint that something _might_ be wrong, I'd say those 26 have
code smell, but the remaining 320 or so do not automatically raise concern (I
inspected those 26 in detail and saw only 4 or 5 cases that'd be removed next
time the code got refactored).
If you use it every once in a while where it is the right solution, great.
I do too. If you're using it every other function in a module, and it
isn't a thin wrapper around some other library, you've got a code smell.
I found that multiple return values were not often used in "public" functions
(those meant to be accessible from outside the module). Instead the most common
use case was between functions that had been separated to divide the problem
into smaller, testable code chunks (i.e. - rather than having a huge function to
parse a log line, perform computations, and send the results to output, there
was a function that'd take the raw data, call a helper function to parse it,
call another helper to compute the result, and call another to send the results
off for output)
Without the ability to return multiple values, it would be much more cumbersome
to split the code into small, easily understood chunks because for any
non-trivial task, each logical "step" in that task often has multiple inputs as
well as multiple outputs.
After reviewing the code, I think that the use of multiple return values is, in
and of itself, _almost never_ a good hint of a problem - way too many false
positives (a better rule of thumb would be that code that returns BIG tuples has
code small).
(It's probably a class or two trying to get out.)
No, at least not in the code I looked at - in the vast majority of the uses of
multiple return values, the coupling between the functions was already very
tight (specialized) and the callee-caller relationship was one-to-one or
one-to-few (the function returning multiple values was called by one or very few
functions), and the data didn't move around between function as a unit or group,
such that making a class would have been pure overhead like many C structures -
never reused, and used only to cross the "bridge" between the two functions
(immediately unpacked and discarded upon reception).
You've got a *big* code
smell if you are unpacking those return values many times, because now
you've hard coded the size of the tuple into the code in many places.
Yes, this was mentioned previously.
-Dave