I'm still evaluating how well the idea behind multiple-returns works...but by and large, they seem to be working pretty well.
So I've gone ahead and moved them from the "usermode prototype" to natively implementing them as part of the evaluator, which speeds them up by a factor of... a lot.
While doing so, I added a new feature of being able to "circle" which result will be the value of the overall expression. Previously this was always the "main" return value, but now you can pick another via a SYM-WORD!.
Here's a function with a secondary return value to demonstrate with:
multi: func [ return: "Main return value" [integer!] secondary: "Secondary return value" [integer!] ][ if secondary [ ; NULL if not asked for via multi-return (or refinement) set secondary 20 ; reminder: `set # ...` is a no-op ] return 10 ]
Traditionally you could ask for both results, and the overall result would be the first return:
>> [a b]: multi == 10 ; defaults to same value as first result, e.g. a >> a == 10 >> b == 20
But now you can use a SYM-WORD! instead to ask for a different result, e.g. the second:
>> [a @b]: multi == 20 ; same value as b >> a == 10 >> b == 20
You can combine this with things like GROUP!s to calculate the variable name, or even omit the variable name and use
>> [a @(#)]: multi == 20 >> a == 10
There are some places where this comes in handy, although you generally want to pick the main return to be the thing people are most interested in responding to (e.g. determining success or failure of an operation).