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.
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);
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).
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"
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?
Nobody seems to have mentioned Perl yet.
sub myfunc {
return 1, 2;
}
my($val1, $val2) = myfunc();
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.
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.
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
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.
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()) ...
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;
}
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
By the way, Scala can return multiple values as follows (pasted from an interpreter session):
scala> def return2 = (1,2)
return2: (Int, Int)
scala> val (a1,a2) = return2
a1: Int = 1
a2: Int = 2
This is a special case of using pattern matching for assignment.
Here was my Ruby idea to return a special value that looks and acts like a scalar but actually has hidden attributes on it:
来源:https://stackoverflow.com/questions/514038/elegant-ways-to-return-multiple-values-from-a-function