Fog Creek Software
g
Discussion Board




Returning Multiple Values from a Function

Joel said:

<<<
I think the reason programmers in C/C++/Java style languages have been attracted to exceptions is simply because the syntax does not have a concise way to call a function that returns multiple values, so it's hard to write a function that either produces a return value or returns an error. (The only languages I have used extensively that do let you return multiple values nicely are ML and Haskell.)
>>>

Well, I believe in Perl it is also possible to return multiple values. In Perl 5 every function accepts an array of arguments and returns an array of return values. So you can say:

my ($error_code, $ret1, $ret2) = myfunc("hello", $handle);

Shlomi Fish
Wednesday, October 15, 2003

It is possible to return such an array from many languages but then it is difficult to nest the functions, or use them in expressions.  You would have to include logic following the call to check for the error condition instead of allowing the exception to handle it.

john
Wednesday, October 15, 2003

Perl very nicely lets you do this too:

$ret2 = (myfunc("hello", $handle))[2];

If you didn't care about $error_code or $ret1.


Wednesday, October 15, 2003

Returning multiple values in scripting languages is not uncommon.  Python provides a concise mechanism to return and assign multiple values on a single line.

However, you can achieve a similiar effect in C++ by passing by reference.  After the function call, the variables passed by reference can hold data you might otherwise have included in multiple value return statement.

Michael Mata
Wednesday, October 15, 2003

Other options for C++:

1) Return a vector<> from each function.

2) (As proposed elsewhere in this forum) Return a custom object than encapulsates a return value and error code.

3) Set a global status variable after every call (like the VB Err object)

However, none of these are as nice as just returning a status code or raising an exception.

Perhaps (3) could be setup like as a queue; Errors can build up and you can then check them anyway you like:

err.Reset();
x = somefunc();
y = someOtherFunc();
if (err.Count() > 0) {
  // Something bad happened above
  // Print out all errors
}

// Add an error to the queue
Err.Raise(256, "Something bad happened");

Almost Anonymous
Wednesday, October 15, 2003

I've found that, in C++, the easiest method by far is to return a pair<bool, realreturntype>.  Now you've completely separated your return value from your error code.

Trollumination
Wednesday, October 15, 2003

How about user defined types?

Albert D. Kallal
Wednesday, October 15, 2003

Yes, STL already returns pair<bool, whatever> for some functions.  I think the find algorithm, for example.

Roose
Wednesday, October 15, 2003

Perl also lets you return an array or a scalar depending on how the function was called.

This returns a scalar.
$r = &myfun;

This returns an array
@r = &myfunc;

sub myfunc{
return wantarray ?  ("a",1,"hello"): "world";
}

Tom Vu
Wednesday, October 15, 2003

An alternative for pair<bool, realreturntype> might be to use Boost's optional library, i.e. to return an optional<realreturntype>.

See http://www.boost.org/libs/optional/doc/optional.html for an example.

- Roland
Thursday, October 16, 2003

In PHP and Python, it is also possible to return multiple values!

Jed
Thursday, October 16, 2003

Ruby has multiple return values as well. 

It's great for concise code.

    name, age, telephonenumber = line.split(/\t+/)

For error handling, however, I think it would be horrible.

The rescue clause is much, much nicer.

Ged Byrne
Thursday, October 16, 2003

Any language that supports returning objects, pointers, arrays, or references can simulate returning multiple values. That isn't the problem.

If your function uses the return code as an error code, the function is crippled because every use of it must be surrounded by error handling--you can't write clear, obvious code that uses the result of one function call as input to another.

Returning multiple values does not make this any better.

To me the exception-based style is cleaner and easier to read than the error code checking style. Not always, but most of the time. For example (in Python):

  try:
      saveZip( cleanZip( getHTMLForm("zip")))
  catch ValueError:
      errormsg = "Please enter a five-digit Zip code"

Is, TO ME, clearer than this:

  zip = getHTMLForm("zip")
  (ec, zip) = cleanZip(zip)
  if ec == 0:
      saveZip(zip)
  elif ec == 1:
      errormsg = "Please enter a five-digit Zip code"

In the first example I can clearly see the intention of the code: get a zip code from an HTML form, clean/validate it, and save it somewhere. And I can clearly see how the possible errors are handled.

With a language that doesn't support multiple return values I'd have to make cleanZip modify an input parameter, which means even more problems: I can't pass a function call as a parameter (have to use a temporary variable), and I'd have to know from looking at the call that a parameter I passed will be modified by the function. Yuck--no locality of information there!

This is an example to illustrate my point, not meant as production code or a display of my ignorance of Zip+4 or Canadian postal codes. I didn't even check that it's correct Python code. Please don't go off into the weeds analyzing the code.

Gregory Jorgensen
Thursday, October 16, 2003

*  Recent Topics

*  Fog Creek Home