@zwarich @dotstdy @ianh @joe Related, but why isn't first class multiple return values a thing more often?
For example, the C++26 standard library has senders/receivers which essentially work via continuations, so you can write async functions that take N inputs and M outputs natively without resorting to tuples. You can even send outputs of different types without having to box them into a sum type (because they just statically dispatch to different overloads).
@joe @foonathan @dotstdy @ianh I think most languages that would allow you to return borrows would let you also store them as struct fields, etc. and just add a borrowed pointer type, in which case you could just make a tuple of borrows. I guess you could take a purist "parameter modes" approach and define borrowed struct fields via parameter modes on the struct's constructor? However, I think it might be tricky to make this work well with generics.
Another place where a similar distinction comes up is in-place construction of return values. Rust doesn't have this, but I assume that some successor language will want this to support internal self-reference, e.g. for efficient containers with inline capacity
@zwarich @foonathan @dotstdy @ianh yeah return value emplacement was the other thing i had in mind where a tuple (in its naive unexploded representation) isn't the same thing as multiple values.
even with first-class borrows, the way swift tries to allow for tuples to be magically exploded and imploded by the implementation fights against the very concept of a borrow-of-tuple ever existing, since you really want a contiguous representation for that borrow to refer to
@joe @foonathan @dotstdy @ianh Another funny realization is that if all return values are returned by writing to a passed reference, then you could have functions with no actual return values and only out-params (with the appropriate pointer type that must be written before returning). It's the use of resources like registers (which may be implicitly used by other code in the function) that necessitates presenting a value at the point of return.
You could take this to the next level and actually have out-params that "steal" registers when written to, but at that point you're probably in meme language territory.