Having multiple return values is preferable. Lacking them is bad design, plain and simple. However, we should clear up the misconception that such a thing even exists in the sense you are thinking of.
In languages based on the typed lambda-calculus (the progenitor programming languages), e.g. ML-family, Haskell, a function (lambda abstraction) only accepts a single argument and "returns" (more formally, evaluates to) a single result. So how can we create a function that seems to take or return multiple values?
The answer is that we can "glue" values together by using product types. If A and B are both types, then the product type $A \times B$ contains all tuples of the form $(a, b)$, where $a: A$ and $b: B$.
Thus, to create a function multiply
that multiplies two integers together, we give it the type multiply: int * int -> int
. It accepts a single argument which happens to be a tuple. Likewise, a function split
that splits a list into two would have type split: a list -> a list * a list
.
Maybe 30 years ago implementation was a valid concern in including such a feature. According to the C calling convention cedl (and it is just that, a convention - no god ordained it), the return value is stored in a special register, usually EAX
. Certainly, this is extremely fast to read and write, so the idea has some merit.
But it is too limiting, as you point out, and there is no reason we need to follow this rule nowadays. For example, we could instead use the following policy: for a small number of return values, use a set of specified registers (we have more registers for use now than in the 80s). For larger data, we could return a pointer to a location in memory. I don't know what's best; I'm not a compiler writer. But the archaic C calling convention should have no influence on the semantics of modern languages.
i=0; while (true) { return i; i+=1 }
?). Note that some functional languages offer tuples, a better alternative. $\endgroup$return
statement. When returning functions/lambdas, you may have a point. $\endgroup$