views:

3680

answers:

13

It seems like in most mainstream programming languages, returning multiple values from a function is an extremely awkward thing. The typical solutions are to make either a struct or a plain old data class and return that, or to pass at least some of the parameters by reference or pointer instead of returning them. Using references/pointers is pretty awkward because it relies on side effects and means you have yet another parameter to pass. The class/struct solution is also IMHO pretty awkward because you then end up with a million little classes/structs that are only used to return values from functions, generating unnecessary clutter and verbosity. Furthermore, a lot of times there's one return value that is always needed, and the rest are only used by the caller in certain circumstances. Neither of these solutions allow the caller to ignore unneeded return types.

The one language I'm aware of that handles multiple return values elegantly is Python. For those of you who are unfamiliar, it uses tuple unpacking:

a, b = foo(c)  # a and b are regular variables.
myTuple = foo(c)  # myTuple is a tuple of (a, b)

Does anyone have any other good solutions to this problem? Both idioms that work in existing mainstream languages besides Python and language-level solutions you've seen in non-mainstream languages are welcome.

+1  A: 

i thinks python's is the most natural way, when I had to do same thing in php the only was to wrap return into an array. it does have similar unpacking though.

SilentGhost
A: 

Often in php I'll use a referenced input:

public function Validates(&$errors=array()) {
   if($failstest) {
      $errors[] = "It failed";
      return false;
   } else {
      return true;
   }
}

That gives me the error messages I want without polluting the bool return, so I can still do:

if($this->Validates()) ...
willoller
did you mean Validates in both cases and it's just a typo?
SilentGhost
+17  A: 

Pretty much all ML-influenced functional langues (which is most of them) also have great tuple support that makes this sort of thing trivial.

For C++ I like boost::tuple plus boost::tie (or std::tr1 if you have it)

typedef boost::tuple<double,double,double> XYZ;

XYZ foo();

double x,y,z;
boost::tie(x,y,z) = foo();

or a less contrived example

MyMultimap::iterator lower,upper;
boost::tie(lower,upper) = some_map.equal_range(key);
Indeed, Python's syntax is almost certainly deliberately taken from the functional programming world.
bobince
Awesome. I should really write something like this for D. If it can be done in C++, I'm sure it's trivial with D templates.
dsimcha
@dsimcha http://www.digitalmars.com/d/2.0/tuple.html can get you started :)
ephemient
Yeah, I did it already. It was pretty trivial. I already was a heavy user of tuples, but getting the syntactic sugar for the unpacking right was non-trivial.
dsimcha
if you want to return only two values you can use std::pair as well
Janusz
Trivial, yes, but you lose meaning in your return. What does the second double of the tuple mean? Your guess is as good as mine.
Will
+5  A: 

If a function returns multiple values, that is a sign you might be witnessing the "Data Clump" code smell. Often data clumps are primitive values that nobody thinks to turn into an object, but interesting stuff happens as you begin to look for behavior to move into the new objects.

Writing tiny helper classes might be extra typing, but it provides clear names and strong type checking. Developers maintaining your code will appreciate it. And useful small classes often grow up to be used in other code.

Also, if a function returns multiple values, then it might be doing too much work. Could the function be refactored into two (or more) small functions?

cpeterso
I disagree completely. Yes, multiple return values are something bad programmers do. But *not everything has to have its own object or class*. Tuples are a perfectly valid data type in their own right, and to return a tuple of logically-connected values is just fine.
kquinn
A good example is a function that returns counts of something, eg, numUpdated, numDeleted, numUnchanged. Creating a class is overkill for 3 ints. WRT Java, its not too hard to create a Tuple<X,Y,Z> class to handle the common n=2-3 cases (though its pretty verbose in practice).
Richard Levasseur
+1. I agree with commenters that native tuples are very nice to have when there really isn't additional object behavior, but I agree with the answer that it's worth a second thought when you find yourself returning multiple values, and this is good advice on what to think about.
Carl Meyer
Returning multiple unrelated values does smell bad, but multiple related values smell much better.
David Thornley
@ Richard Levasseur: I'd disagree. In your example, if you just return a tuple, it's easy to mix up the values (particularly as they are all of the same type). This is precisely where a class would help. Both when actually writing calls to the function, and when reading/debugging that code, because the meaning of the return values is explicit.
sleske
+8  A: 

A few languages, notably Lisp and JavaScript, have a feature called destructuring assignment or destructuring bind. This is essentially tuple unpacking on steroids: rather than being limited to sequences like tuples, lists, or generators, you can unpack more complex object structures in an assignment statement. For more details, see here for the Lisp version or here for the (rather more readable) JavaScript version.

Other than that, I don't know of many language features for dealing with multiple return values generally. However, there are a few specific uses of multiple return values that can often be replaced by other language features. For example, if one of the values is an error code, it might be better replaced with an exception.

While creating new classes to hold multiple return values feels like clutter, the fact that you're returning those values together is often a sign that your code will be better overall once the class is created. In particular, other functions that deal with the same data can then move to the new class, which may make your code easier to follow. This isn't universally true, but it's worth considering. (Cpeterso's answer about data clumps expresses this in more detail).

Moss Collum
The JavaScript one is awesome. Only newer browsers, though, of course. Can't use the dang thing yet.
Nosredna
Python's assignments supports any iterable: a, b, c = [0,1,2] or even generators like a, b, c = xrange(3)
dF
Thanks, dF--I've updated my post to reflect that.
Moss Collum
Common Lisp also has `multiple-value-bind`.
Svante
The ML family of languages also have the feature you mention for Lisp and JS. Of course the ML family also gives you type safety :-)
harms
+1  A: 

Nobody seems to have mentioned Perl yet.

sub myfunc {
  return 1, 2;
}
my($val1, $val2) = myfunc();
Glomek
+4  A: 

PHP example:

function my_funct() {
    $x = "hello";
    $y = "world";
    return array($x, $y);
}

Then, when run:

list($x, $y) = my_funct();
echo $x.' '.$y; // "hello world"
Evan Fosmark
Wow, that's actually a pretty nice way to do it. I was searching for whether returning an array or passing parameters by reference was the best solution. This seems to me the way I would want to do it. Thumbs up for PHP :)
Matthijs Wessels
A: 

In C++ you can pass a container into the function so the function can fill it:

void getValues(std::vector<int>* result){
  result->push_back(2);
  result->push_back(6);
  result->push_back(73);
}

You could also have the function return a smart pointer (use shared_ptr) to a vector:

boost::shared_ptr< std::vector<int> > getValues(){
  boost::shared_ptr< std::vector<int> > vec(new std::vector<int>(3));
  (*vec)[0] = 2;
  (*vec)[1] = 6;
  (*vec)[2] = 73;
  return vec; 
}
BTW, everytime I deal with a pointer to a vector, I wonder why vec->[0] is not correct snytax and I have to write the ugly (*vec)[0]. Or am I missing something?
@dehmann: `[0]` is not a member of object pointed to by `vec`. `vec->[0]` means `(*vec).[0]` which is not what you want.
Lazer
+2  A: 

Even if you ignore the wonderful newer destructuring assignment Moss Collum mentioned, JavaScript is pretty nice on returning multiple results.

function give7and5() {
  return {x:7,y:5};
}

a=give7and5();
console.log(a.x,a.y);

7  5
Nosredna
I, too, would like to use the newer syntax but it's not supported in IE7 or IE8 (forget about IE6). Your example suffices for my purposes.
Ray Vega
+3  A: 

As for Java, see Bruce Eckel's Thinking in Java for a nice solution (pp. 621 ff).

In essence, you can define a class equivalent to the following:

public class Pair<T,U> {
    public final T left;
    public final U right;
    public Pair (T t, U u) { left = t; right = u; }
}

You can then use this as the return type for a function, with appropriate type parameters:

public Pair<String,Integer> getAnswer() {
    return new Pair<String,Integer>("the universe", 42);
}

After invoking that function:

Pair<String,Integer> myPair = getAnswer();

you can refer to myPair.left and myPair.right for access to the constituent values.

There are other syntactical sugar options, but the above is the key point.

joel.neely
Yea it works, but that's pretty far from elegant.
MichaelGG
+1  A: 

Both Lua and CLU (by Barbara Liskov's group at MIT) have multiple return values for all functions---it is always the default. I believe the designers of Lua were inspired by CLU. I like having multiple values be the default for calls and returns; I think it is a very elegant way of thinking about things. In Lua and CLU this mechanism is completely independent of tuples and/or records.

The portable assembly language C-- supports multiple return values for its native calling convention but not for the C calling convention. There the idea is to enable a compiler writer to return multiple values in individual hardware registers rather than having to put the values in a clump in memory and return a pointer to that clump (or as in C, have the caller pass a pointer to an empty clump).

Like any mechanism, multiple return values can be abused, but I don't think it is any more unreasonable to have a function return multiple values than it is to have a struct contain multiple values.

Norman Ramsey
A: 

anyone know the same ki9nd of implementation in .net? returning multiple variables of different datatypes from a function?

Mohit
Do not post a question as an answer.
Török Gábor
A: 

c#

public struct tStruct
{
    int x;
    int y;
    string text;
    public tStruct(int nx, int ny, string stext)
    {
         this.x = nx;
         this.y = ny;
         this.text = stext;
    }
}

public tStruct YourFunction()
{
    return new tStruct(50, 100, "hello world");
}

public void YourPrintFunction(string sMessage)
{
    Console.WriteLine(sMessage);
}

in Lua you call

MyVar = YourFunction();
YourPrintfFunction(MyVar.x);
YourPrintfFunction(MyVar.y);
YourPrintfFunction(MyVar.text);

Output: 50 100 hello world

Paul

Paul