How to return multiple values

A comparison of three approaches and the possibilities for Cortex

For I have had too much
Of apple-picking: I am overtired
Of the great harvest I myself desired.
There were ten thousand thousand fruit to touch,
Cherish in hand, lift down, and not let fall.
After Apple-Picking, Robert Frost

You probably have stumbled upon a moment when you want to return multiple values in a function. A typical use case is a success code and an actual value, when null is not enough.

We have at least three methods out there. So let’s go apple picking.

Out parameters

Let’s call it the C# approach, inspired on C’s non-const pointer parameters.

Apple pickApple(out PickAppleError error)
{
error = PickAppleError.AppleTooHigh;
return null;
}

Doesn’t make too much sense the first time you look at it. In general, parameters should be inputs to your function, and its output, depend upon them. That is, not taking into account random numbers generated, or current date-time, or other external variables.

Yes, it’s not quite difficult. But, that it not be difficult doesn’t mean that it’s the right way. I’ll dare say that it’s semantically wrong.

Make a class

Let’s call this the Java approach. I would be hesitant to say that this is an established pattern, but it appears to be in use e.g. in Optional, heavily used in the Stream framework, which I have not extensively used, though.

PickAppleResult pickApple() {
return new PickAppleResult(PickAppleError.APPLE_TOO_HIGH,
null);
}

class PickAppleResult {
final PickAppleError error;
final Apple apple;
PickAppleResult(PickAppleError error, Apple apple) {
this.error = error;
this.apple = apple;
}
}

Not very nice, and bloats the system with poltergeist classes. Getting the value out of the function does also introduce a lot of otherwise unnecessary code:

PickAppleResult result = pickApple();
// now unpack
PickAppleError e = result.error;
Apple a = result.apple;

These people say we have either this constantly annoying creation of otherwise unnecessary classes, or should use third-party libraries for tuples. In Java, tuples could help not have to write a dedicated class, but are as painful to unpack.

Tuples as a return value

Let’s call it the Python approach.

We can return multiple comma-separated value; wherein the comma is a tuple operator.

def pick_apple():
return APPLE_TOO_HIGH, null

One could argue that this is a code smell, since one should’t use collections whose elements have distinct semantics depending on position (more here). However, because in Python one can unpack tuples or lists, we can choose never to let it look like a collection. Take:

# BAD!
result = pick_apple()
error = result[0]
apple = result[1]

Now consider:

error, apple = pick_apple()

Much better.

I would only almost complain that it could defy a tiny bit the preference that one line of code should do one thing, and well. But that’s overreaching.


Apple picking with Cortex

Cortex is similar to C# or Java where it only allows variables with static types as of now. However, we want to make things not just work, but work bestest.

Because we feel that output=return and input=parameters, we would avoid choosing to introduce oxymoronic out parameters in our grammar.

The Python approach looks good, but we will probably not support list unpacking because our lists are typed and because we feel that it will hinder performance.

We will also rather avoid encouraging creation classes to support this.

Returning values should be a matter of expressivity, of language design, not solved through design patterns.

Please don’t say that that’d be a design pattern and it’s a well established blah blah. As others have pointed out, recurring on design patterns is a sign that something is missing, or rather, superabundant. It’s WET design.

The solution? Introduce multiple return values as a language construct. Make it fast.

Maybe in some time, this will be Cortex code:

PickAppleError, Apple pickApple():
pickApple = AppleTooHigh, null

And it would be enforced to unpack the result.

PickAppleError error
Apple a
error, a = pickApple()

I will be worried about how well this integrates with comma expressions, existing storage classes, function types, and many more issues.

Maybe one year from now we will end up implementing any of the aforementioned undesirable approaches. And it will exert a hint of fault upon our conscience.

Let’s hope we shan’t be overtired of the great harvest we ourselves desired.

Thanks to Sander, who inspired this article by asking me for an opinion on out parameters☺.

Spread the Cortex ❤.


P.S. Later on when I wrote this, I found out that Kotlin and Swift support multiple return values too. Will read about that later.