Multiple Return Values


#1

We now have the mythical SET-BLOCK! and GET-BLOCK!. You can write:

multi-return: function [a b] [
    return :[(a * 3) (b - 16)]
]

>> [x y]: multi-return 10 20
== [30 4]

>> x
== 30

>> y
== 4

That's relatively cool. And you don't have to take all the values...

>> [x]: [10 20]
== [10 20]

>> x
== 10

You have to know that it's returning multiple values though. Using a plain SET-WORD! will get you the block:

>> x: some-function-i-didnt-know-was-multi-return ...
== [ret1 ret2 ret3]  ; the block! could easily be mistaken for single return

But I've been having one of those ideas that just won't go away...

Rather than choose between [x]: and [x y]: and knowing in advance how many values you're taking or throwing away, I've wanted someone who only wants one value to be blissfully ignorant. So the choice would be between:

>> x: multi-return ...
>> [x y]: multi-return ...

So even though the first case is a multiple return, you wouldn't set x to a block of values, but just get the first value.

This would require some kind of magic.

Here's a stab at what "magic" might look like...

What if AT-BLOCK! ("new LIT-BLOCK!?") wasn't just inert, but had a special relationship with SET, SET-BLOCK!s and SET-WORD!s?

>> reduce [@[10 20]]
== @[10 20]

>> reduce [x: @[10 20]]
== 10  ; the 20 just vaporizes in the assignment
>> x
== 10

>> reduce [[x y]: @[10 20]]
== [10 20]
>> x
== 10
>> y
== 20

This would let you upgrade functions to have more return values without the user knowing it.

The only catch is when you're trying to work with these AT-BLOCK!s literally. Assignment is such a foundational thing that undermining it has consequences.

You'd need a way to do a hard SET. That could be done via SET/ONLY or similar. But for a briefer notation, perhaps SET-GROUP! could be a SET/ONLY?

>> (x): @[10 20]
== @[10 20]

>> x
== @[10 20]

It seems so incredibly useful that I feel we must try something along these lines, even if just to put the notion out of my head so I don't keep thinking about it!


Where the Series Ends: Simplifying Out of Bounds Rules
#2

Yup, sounds really useful.
One question, what do functions see?

f: function [a][]
f multi-return

Does f get the return as a block, or the first value?

What happens with multiple parameters in f? With refinements? With variadics? When f is enfixed?


#3

That's six questions. :slight_smile: But good ones...

what do functions see?

Yep, this is the slippery bit. It's difficult when you have:

data: [1 <a> @[b c]]
foo: pick data 3

If PICK comes back with @[b c] it will look like a multi-return. So it's like PICK has to be marked as not a multi-returning function, and the evaluator knows not to treat it as such.

So that might suggest this is a narrow feature about the behavior of SET-BLOCK!s and a certain kind of function. It may be that AT-BLOCK!s don't have anything to do with it.

In such a case, if you wanted to pass the multiple returns you might have to use some-func :(multi-func ...) or another notation if you wanted to ask for the full value as an argument.

Definitely a lot of thinking to do here, feel free to write up some examples... I just wanted to mention it as something that it seems like we're actually able to look into now, that I think would be cool.


#4

It seems like a lua feature. Multiple return values that work with multiple assignment of variables, but also of the parameters of a calling function.