1. Designing a performant multiple return values mechanism is very subtle. For instance, see J. Michael Ashley, R. Kent Dybvig: An Efficient Implementation of Multiple Return Values in Scheme. LISP and Functional Programming 1994: 140-149.
2. Write me the identity function. (No, really. Stop. Try. Then read on.)
.
.
.
.
.
I hope you didn't say it's
fun id(x): x;
because if F returns multiple values and G consumes them, I can't refactor G(F(...)) into G(id(F(...))), which is pretty much the definition of an identity function. You should see the true identity function in R5+RS Scheme....
3. The way to make simple functions like that continue to work is to make the return values not be multiple values but a single one (i.e., some kind of tuple). At which point...
4. Pyret's objects are very lightweight. They don't carry baggage à la those in JavaScript, etc.
5. If you have multiple values, every single library function has to be rewritten to work with them. What should map do? filter? fold? And the hundred other library functions? It's also really hard to remember this when writing every line of library code (see #2).
6. We'd need a new binding construct in the language to bind the multiple return values. That's yet more syntax design, but also, it's yet more opportunity for typos to turn into indecipherable error messages ("Expected two values, got one" is a horrible thing to read for someone who doesn't even know a function can return two values!).
So, I claim this is simply not worth the frequency with which you actually need precisely this, as opposed to just returning some sort of tuple or object. Also, once I've bound the return value (say to r), saying r.x and r.y instead of just x and y is really not a big deal.