I had an observation that we can actually do multiple return values today, with enfix and skippable parameters:
Imagine you want to make something where it returns the sum of two values and the difference...but only the sum if you aren't using a multi-return.
sum-and-difference: enfixed func [:left [<skip> set-block!] arg1 arg2] [ let sum: arg1 + arg2 ; always returned, only calculate once if set? 'left [ switch length of left [ 1 [ ; we have `[x]: ...` act the same as `x: ...` set left/1 sum ] 2 [ ; only calculate difference for multiple returns set left/1 sum set left/2 arg1 - arg2 ] fail "sum-and-difference can only return 1 or 2 values" ] ] return sum ]
>> x: sum-and-difference 20 10 == 30 ; handled by plain evaluator mechanics >> [y z]: sum-and-difference 20 10 == 30 ; handled by the enfix quoting >> y == 30 >> z == 10
Notice that adopts the principle that it doesn't actually try to return a BLOCK! with the multiple return values, but only the first value. But the interesting bit is that when you go about it this way, the convention is not really enforced.
what's wrong with doing it this way?
A disadvantage of this technique is it means you cannot make enfixed functions that have multiple return values (in the sense they've already used their enfixedness for the purpose of the multiple return value itself).
That may or may not be bad. :-/ This offers a lot of flexibility to people for designing how their multiple return values work. They could decide that blanks mean skip the assignment, so for [_ z]: sum-and-difference 20 10 it could be decided not to calculate the sum at all, and to return the difference. Or people who disagree with my philosophy about return the first thing could come up with their own rules...returning blocks that voidify, or maybe even the ability to mark which thing to return like [y @z]: sum-and-difference 20 10 could calculate both but return the difference.
We could build any of those ideas in--but telling people they are their own boss and can design it how they want is a powerful idea that is a bit unnerving. Though Rebol has a lot of those. Truly a strange way of looking at multiple return value mechanics.
But it's still cool just in terms of prototyping--as well as to show that the mechanics aren't that far out. I feel like the interface for multiple-returns should be something along these lines, e.g. if you say func
[return: [<multi>] ...] what you actually get is some way to address the variables that you are assigning...basically an analogue to being sensitive to the contents SET-BLOCK! from the left (though maybe for information-hiding purposes you could only know if an assignment was desired, and not be able to read the previous values from the left-hand side).