Multiple return values have an interesting angle to them: the more values you request... the functionality you ask for might wind up being different.
Consider TRANSCODE. If you don't use multi-returns...or just ask for one return...you get the whole thing transcoded as a block:
>> transcode "<abc> <def>" ; plain behavior == [<abc> <def>] >> block: transcode "<abc> <def>" ; set-word! (follows usual rules) == [<abc> <def>] >> [block]: transcode "<abc> <def>" ; same behavior as `block:`, enforced == [<abc> <def>]
But if you supply it with a parameter in the second slot, it assumes you want /NEXT and will set that argument to the next position.
>> [value pos]: transcode "<abc> <def>" == <abc> >> pos == " <def>" >> value == <abc>
BLANK! gives you the ability to opt out of slots in the multiple return values that you don't want. But opting out doesn't just keep you from having to name a variable, it also un-requests the behavior...
>> [value _]: transcode "<abc> <def>" == [<abc> <def>] ; not a /NEXT, it was "revoked"
What if you want to request the behavior, but not have to bother with creating a variable to store it in? Well now that we are thinking # will be a shorthand for the immutable and not-appendable-to-strings "codepoint 0", it's a perfect choice:
>> [value #]: transcode "<abc> <def>" == <abc> ; only the /NEXT item
The value was requested but disappeared...into a black hole. In fact, BLACKHOLE! is now a datatype you can put in a spec to mean "empty issue that is precisely
#. It's not validated yet (it's a synonym for ISSUE!...we'll need type constraints before it can work). But it can help keep track of places that use this idea. For instance, SET:
>> set # 10 == 10
The truthiness of # helps write code that distinguishes the wish to opt-out of a behavior from the wish to opt-out of getting its result. Having SET error on blank helps you avoid calculations that may be unnecessary...so it works out perfectly:
do-something: func [ return: [...] secondary: [blank! word! path! blackhole!] input <local> result ][ main-result: process input if secondary [ ; unlike BLANK!, empty issue is truthy so branch runs result: process/more input set secondary result ; blackhole SET is no-op (BLANK! would error) ] ]