I am not sure whether I would call this specific instance blogspam. It is a curated series arstechnica runs together with stackoverflow that presents the most interesting excerpts.
It's pretty worthless, whatever you choose to call it. For one, it adds nothing to the original SO page - no commentary, insight, etc. For another, it doesn't update dynamically, so is already out of date. It's now just duplicating information that will no doubt be refined, so is pretty much having a net-negative effect - exactly the kind of content SO was originally set up to improve upon / obsolete.
I'm unfortunately finding Ars more and more like this. Where I once went for novel tech insight and reviews, I now see posts ''curated'' from around the web, and a growing lifehacker-esque quality.
That might be true for you, but that still doesn't make it blogspam, necessarily.
Content curation is a tried and true technique that some people love. I like reading the SO articles by arstechnica because I don't have to sift through the whole thread _and_ because they are stable, so you know what you link to.
YMMV, but it is definitely more than just copying and excerpt and setting a link, especially as the orginal platform is involved.
Racket can actually return multiple values rather than a product type, which is what Python does. However people don't usually use it because it's easier to just return a pair or whatever and then pattern match on it.
Common Lisp can do the same thing, and people typically prefer returning a product type because capturing multiple return values invariably introduces some extra syntax.
Forth functions (or words, if you insist) can return multiple values as easily as they can return a single value, but the stack metaphor makes this a lot more natural. This is also true of Joy and RPL and other languages which are conceptually organized around mutating a (notional) stack. Multiple return values only become unnatural when you choose an abstraction other than the stack.
It seems to me that some domain-specific computations are better modeled with the ability to return multiple values. For example, digital signal processing - a handy abstraction in DSP is the idea of having "blocks" and simply connecting the outputs of some blocks to the inputs of other blocks. A block in this model can be viewed as a function which is executed continuously.
I've come across the thought myself from time to time... usually have to end up creating objects/structs to then return, though in the past when I've been lazy (on iOS) I've chunked things into NSArray/NSDictionary.
But darn, I can't remember specific examples right now, I know I've definitely had moments where returning multiple things would have been nice lol.
I've found returning type and boolean useful more than once, usually 'data of type and false if something went wrong or the return data is invalid, data of type and true if valid.'
std::pair<T, boolean> was like a gift from the gods when I found out about it
The stated reasons are all stupid. The real answer is likely that programming language design is largely a cargo cult exercise and early languages only had single return values, which are easier to implement.
I have to agree. I found the answers to be mostly after-the-fact justifications, rather painful to read in fact. Sure, y = sin(x) is well modeled as having one output, but there are plenty of multi-output functions, even in math. A few that come to mind are:
Modulus calculations like
a,b = mod(x,n)
where a is the remainder modulo n, and b is the residual, so that x = a + b*n.
The two outputs from the quadratic formula.
All the matrix factorizations, such as
L,U,P = lu(A)
where A = P L U, and L and U are triangular, and P is a permutation.
The remedy of having a data structure to hold the a and b integers above, or the two roots of a quadratic equation, is asinine.
It's exactly like that in Haskell. If it makes sense to return 2 values — return tuple. Works really well with pattern matching. Syntactic overhead = 0.
Considering there's an entire academic discipline of programming theory I strongly disagree with the description of language design as "cargo-cultism".
Only a few languages are the product of that theoretical discipline. There is, for example, a clear theoretical reason why Haskell functions are single input single output. But its inapplicable to nearly all languages. The languages people use are mostly the result of cargo cultism.
Theory aside, it would seem natural that a language that doesn't enforce 1-argument functions would have n-argument functions. Seems like the only logical two choices on the matter. Where does the cargo-cult in this decision come in?
It is considered cargo-cultism mostly because none of the languages ever have any scientific data to support decisions on various syntax choices. There are some very obvious bad choices of course, because of the large amount of bugs involving them, like manual memory management and pointer arithmetic, but other than that it's all just a hunch.
I don't understand why there is there a connection between syntax choice and cargo cult design? If anything syntax is the most solved part of language design.
Cargo-cultism is the duplication of the appearance of functioning systems or structures in a context where they are nonfunctional or incorrectly functional. Copying the functionality of an existing system isn't a cargo cult.
The persistence of features in programming languages you're describing isn't a cargo cult because the resulting products work. In addition, there's several benefits of conservative language development: it's generally easier to write compilers; existing programmers will find it easier to adopt a language that mostly resembles ones they already know; and some unfashionable but useful features may be retained.
This is more of a "worse is better" situation than a "cargo cult" one.
I use multiple return values in Python all the time. Returning tuples (which due to multiple assignment actually work / appear as multiple return values). And using continuations, generator functions, etc.
Assume a language where functions do not only return one value. Now, consider each function in this language. It either returns the same number of values each time, where each has a specific meaning, and they are distinguished either by order or by name. Or it returns an arbitrary number of values, where the semantics of each are the same. But that means the return values are equivalent to a tuple, a dictionary, or an array, which are single values. Therefore we have a contradiction and such a language does not exist. (Yes, I know about values in Lisp and this can be a bit nice. Mostly joking.)
More seriously, ask the question: what relationship between multiple values is useful for returning from functions but not useful enough to be a data structure that can be used in other parts of code?
The same argument applies to functions with multiple parameters, and yet most languages support multiple arguments rather than requiring one to use tuples.
For that matter, Ada used parentheses for array offset and for function calls, on the grounds that both map between values. Others, of course, say that this was really because DOD owned so many old keyboards without square braces.
But, that is a bit different. Function calls return one value because expressions evaluate to one value. Functions accept multiple arguments the same way any expression can be made up of multiple values. What the formal parameters allow is a kind of destructuring assignment to give new names to values. (This is especially clear in eg. Clojure.)
Returning from a function is calling the caller's continuation. If functions take multiple parameters, why not continuations?
Semantically I think it's a lot cleaner to make every function 1-in 1-out. Multiple parameters are just a disguise of passing a tuple. In dynamically typed languages, though, it's difficult to make it efficient.
>> More seriously, ask the question: what relationship between multiple values is useful for returning from functions but not useful enough to be a data structure that can be used in other parts of code?
Any metadata about that particular function call.
E.g. function success / effectiveness (did state change?). Runtime. Memory usage.
EDIT: I think co-dependants are still the primary use case, im just suggesting another less obvious use case.
Why not have these on data? If they only get returned from one function call, you have to manually deal with them in each function. If attached to data, they can get aggregated over large chains of fn calls.
Why pollute your data objects when you could just return a separate object at the same time?
Improves cohesion. Seperates responsibilities. Removes duplication and redundancy.
When you pass the metadata off for aggregation or other processing with this multi return model, you dont pull along a chunk of irrelevant business data at the time.
> More seriously, ask the question: what relationship between multiple values is useful for returning from functions but not useful enough to be a data structure that can be used in other parts of code?
Sometimes there are pieces of data which are hard to create a cohesive type around. That is, you can compose an new type from other types, but you can't really add any behavior to that new type. This is exemplified by the Tuple type in many languages: it's basically a hack to treat disparate pieces of data as one, and it doesn't offer any way to operate on its own data.
Here's an example from a relatively typical idiom of parsing an int from a string:
int parsedInt;
if(int.TryParse(s, out parsedInt))
{
Console.WriteLine("Parsed {0}",parsedInt);
}
else
{
Console.WriteLine("{0} was not an integer",s);
}
The problem here is that TryParse() really returns two values, one of which will be tested to see if the parse was successful, and the other of which is assigned to parseInt. You could test that the string can be parsed and then get the parsed value in two separate functions, but this would be inefficient because you'd essentially have to parse the string twice. I'm on my Mac so I'm not sure I'm remembering this correctly, but I think C# forces you to put the "out" there, which I think is good because it clarifies that parsedInt will be assigned. However, I think there are a number of ways in which the following (hypothetical) redefinition of TryParse (and C# syntax) feels a lot clearer:
var parseSucceeded, parsedInt = int.TryParse(s);
if(parseSucceeded)
{
Console.WriteLine("Parsed {0}",parsedInt);
}
else
{
Console.WriteLine("{0} was not an integer",s);
}
First of all, the programmer has been forced to assign the success boolean to a clarifying variable. Second, the call has a clearer structure: the input are on the right side of the = and the outputs are on the left.
Let's look at some other possible solutions here:
var parseTuple = int.TryParse(s);
if(parseTuple.Item1)
{
Console.WriteLine("Parsed {0}",parseTuple.Item2);
}
else
{
Console.WriteLine("{0} was not an integer",s);
}
This results in some confusing code. Item1 and Item2 are very poor names for the things they represent.
IntegerParseResult parseResult = int.TryParse(s); // Didn't use var here to clarify what this code means.
if(parseResult.ParseSucceeded)
{
Console.WriteLine("Parsed {0}",parseTuple.ParsedInt);
}
else
{
Console.WriteLine("{0} was not an integer",s);
}
This is a little better, but the creation of a whole new type seems heavyweight, especially given that this new type provides no real functionality. It's tying together two pieces of data which are about to be separated and never used together again (consider, for example, that instead of printing to the console it might return).
I guess the argument I'm making here is that just because a function returns to outputs doesn't mean those outputs have a meaningful relationship that would justify having a new type.
I think that's a bad example, because your TryParse function can be thought of as returning a value wrapped in a monad. A Maybe monad, to be specific. In Haskell:
case (tryParse s) of
Just n -> putStrLn "Parsed " ++ (show n)
Nothing -> putStrLn (s ++ " was not an integer")
Nothing is a very convenient little concept: It's a value which isn't a 'legitimate' value in any context. It's always a flag value. In C, for example, there's no way to have a flag value of type int in this context, because tryParse could conceivably return any value of type int as its legitimate result. It's also wonderfully conceptually clean: The function either just returns a legitimate value or it returns nothing legitimate at all, and you always know which it did. The point is, however, it only returns one value, and doesn't rely on any out-of-band communications through errno or similar.
If you want to get fancy, you can use the Either monad. This can allow you to say why a parse failed, for example:
case (tryParse s) of
Left n -> putStrLn "Parsed " ++ (show n)
Right m -> putStrLn "Parse of " ++ s ++ " failed because " ++ m
In this case, tryParse would have the type:
tryParse :: String -> Either Int String
The point here is, you still only return one value, but they can be either of two different kinds of value, as distinguished by being tagged either Left or Right, and can even be different types. Again, one value, no out-of-band signalling.
And, of course, Haskell has tuples. You can do interesting things without them, however.
C# has kind of an equivalent of that, at least for this purpose, of nullable value types. Thus, you could do:
int? result = int.TryParse(s);
if(result.HasValue)
{
Console.WriteLine("Parsed {0}",result.Value);
}
else
{
Console.WriteLine("{0} was not an integer",s);
}
And in C#, you could do the second kinda like:
object result = int.TryParse(s);
if(result is int)
{
Console.WriteLine("Parsed {0}",result);
}
else
{
Console.WriteLine("{0} was not an integer",s);
}
Though there's nowhere simple to make it clear that this TryParse either returns the parsed int, or a string describing why the parse failed. And returning object kinda goes against the spirit of the language, IMHO.
Perl's context addresses this in a useful way; a function can be called in a void context (no value expected), a scalar context (one value expected) or a list context (multiple values expected.) The function can detect which context it's being called in and alter it's response accordingly.
List context works really well with list assignment, which lets you assign multiple return values directly to muliple scalar variables. It also works well with passing multiple return values to the input of another function, of course.
Generalizing, there's really a math relation but it's most because the language designer wanted this. Nobody wanted to add this feature (not so trivial to a compiler) if they just could return a struct.
Most? Isn't "pass by reference" a feature of most languages? But yeah "mathematical constructs" don't most kids learn functions in elementary school? How is this front page news?
The real answer is "most languages can return multiple values", since whenever structs were introduced. And if you're bugged by the fact that there are multiple input parameters, well, just think of the list of params as a tuple. Which you could picture as anonymous structs anyways.
So that in the end, all functions take one tuple and return one tuple, where tuples can be called structs, classes, or, well, tuples.
The real question being, why is it that there is a syntactic sugar for anonymous input structs but that the sugar for output structs is just being introduced.
It's pretty simple IMO: supporting multiple return values constitutes unnecessary language complexity once you have tuples in your language (which you should, because they are extremely simple and generalize to many other patterns beyond returning multiple values).
In many cases, I do think it's the right decision to only support one argument per function, but I explained why Rust doesn't do that here: https://news.ycombinator.com/item?id=6949077
Common Lisp has multiple return values and it's quite useful:
(let x (f 12) ...) ; bind x to the first value returned by (f 12) and silently drop the others
(let (x y) (f 12) ...) ; bind x to the first value and y to the second.
That way, I can return more information without breaking existing code. That point is really important: in Python I can gracefully add an extra argument, from
def foo(x):
...
to
def foo(x, y=None):
...
but I can't return an extra value without changing (and uglifying!) all calling code to handle the tuple.
The answer to the OP is probably that all computer languages derive from Fortran, and Fortran derived from maths, so it chose f(x, y) as the notation for function application. With that notation, there's no elegant way of handling more return values, and language designers might feel that the extra complexity/ugliness isn't worth it. That, and intellectual inertia.
(There are also multiple-value-call and multiple-value-list, which are more powerful than multiple-value-bind because they let you get all the values returned without knowing in advance how many there are, but usually less convenient.)
>Common Lisp has multiple return values and it's quite useful:
Ditto for Perl:
sub f { 1..$_[0] }
my ($x) = f(12); # $x = first value, rest are dropped
...
my ($x, $y) = f(12); # $x & $y have first two values, rest are dropped
...
my ($x, $y, @rest) = f(12); # $x=1, $y=2 & @rest=3..12
I still haven't read a really good reason. I use Ruby for most of my personal work, which does infact let you return multiple values in a clean and straightforward way. Though being dynamically typed and not requiring variable declarations probably helps more with that.
I work mostly in C#, and the lack of multiple return values hits me about once a month or so, and I usually have to create a new class just for the purpose of returning two values from one function one time that will never be used again. There's several other possibilities, most of which are even more awkward and annoying - out and ref params, which need some variables declared separately; arrays, lists, and dictionaries, which need either the same type or casting and index by numbers or a string, and tuples, which have strong typing, but name everything Item1, Item2, etc. It might be a good solution if there was support for anonymous functions as return types, but I don't think you can do that right now without using dynamic.
Sounds like C# needs destructuring assignment. In Ruby, you're more or less just returning an array that gets destructured immediately -- "return a, b" works the same as "return [a, b]".
Yeah, I thought of that. The trouble is, in Ruby, that works nicely as syntactic sugar because of the dynamically typed nature of the language. Methods have no declared return types, variables also have no declared types, arrays and other data structures hold any kind of object, and you can try and do anything to any variable, and the interpreter will figure out at runtime if that's possible and throw if it can't do it. When you "return a, b", it's clearly an array of objects, since that's the only array Ruby has, and it doesn't matter what the types of a and b are, since the array can hold any type, and the return type is never declared anyways. When you go to use it, you can do "a, b = foo()", which is fine, since you don't have to declare types of variables anyways. You can try and do anything to those a and b after foo, and the interpreter figures it out at runtime.
In C#, and I expect Java and most other more statically typed languages, you run into all kinds of awkwardness doing this. Arrays and other data structures are strongly typed by default, and number and type of method returns must be declared. You could return a object[], which is easy enough to declare, but then on the call side, you'd have to declare a object[] to receive the return, then individually cast each element to whatever type it's supposed to be before you can do anything with it. Kinda awkward, and against the spirit of the language.
Declaring multiple returns of different types doesn't seem to help much, either, since you can't declare 2 variables of different types on the same line, so you have to declare them both somewhere else, making it about as awkward as using out params.
The best solution I can think of that fits with the spirit of the language is to use anonymous types. You can already do:
var something = new { Foo = a, Bar = b };
something.Foo.DoStuff();
something.Bar.DoStuff();
In that case, the compiler creates a class for "something" for you invisibly, based on the properties you assigned. What's neat about that is that it maintains strong typing of everything, since it figured out the types from the declaration, so you can still do things with the Foo and Bar properties, and it knows what types they are and enforces all of the standard compile-time type checking.
The downside is that you can't return these anonymous types from a method, as the method return type must normally be statically declared. You could return dynamic, but then you lose all of that static type checking, and are back to a slightly cleaner version of returning object[]. I suppose the language authors figured that it's too complex to return anonymous types from methods, as far as figuring out at compile-time what you're actually calling and what it would return.
And now that I think I've successfully argued myself out of what I originally wanted to do with a ridiculous number of words, I'll just give up.
In low level languages such as C, I imagine it was an attempt to map to the machines of the day. It isn't hard to come up with an ABI that allows for returning multiple values, and with registers being thrown into CPUs left and right now days, using 1 more register to allow two return parameters would actually be really nice.
(Of course you'd have to dump anything beyond that onto the stack!)
I imagine the world would be a lot different (or at least a bit less buggy!) if C had allowed for returning an error code in addition to a return value.
Once you get to higher level languages though, the need sort of falls away. Put data into a container of some type, call it a day.
Perhaps the more interesting question is why do most programming languages allow several input values?
I'll make the argument that in Haskell, functions BOTH support only a single input value and a single output value. For example, consider the function (+) which takes two numbers and returns their sum. The type of (+) is (+) :: Num a => a -> (a -> a). I have added the parentheses to emphasize the syntax of the type. (+) is a function which takes a single number as input and gives a single function as output!
Now, we can do something like f :: (a,b) -> (x,y,z) and write:
let (x0,y0,z0) = f (a0,b0)
But this isn't really multiple input or return values. We are just inputting or returning a struct (with constructor (,) or (,,), respectively), and we can pattern match against it for the return value.
I think that any elegant language should support as few "primitive features" as possible - it should be simple, and let a few powerful ideas (e.g., first-class functions, currying, and pattern matching) let the rest fall out. I think Haskell really embodies this idea.
I've thought about switching to only one input value for Rust, but it's needed for the FFI, so once we're paying the complexity there we might as well pay it everywhere. Besides, it'll make it easier to add optional and named parameters if we ever do in the future.
Unfortunately calling conventions are hideously complex; some arguments go in registers, some go on the stack, some change depending on whether they're structs or floats or not…it's a giant mess :(
"The one place they are pretty convenient is in languages (like Python) where multiple return values from one function can be used as multiple input parameters to another."
Python only returns a single value - a tuple. It's just that there is symantic sugar on the functions side to fold multiple values into a tuple, and on the side that's returned to, it's simple value unpacking.
To answer the question, one has to define precisely what "returning multiple values" should mean.
It's hard to see how this is indistinguishable from returning a list/array/tuple plus supporting list destructuring syntactically, even in a limited way. This works in Ruby, for example:
So, you can have a function which returns an Array and the caller can "act" as if it's returning multiple values of mixed types. Python can do the same thing. Does this count as supporting "multiple return values?"
One might think about this mathematically "as if" returning multiple values were the (functional) composition of returning a list and list destructuring. If your language supports lists, you'll always have the ability to return a list, so in a world where one wants to support returning multiple values, why add support for it "directly" when you can add support for something simpler and more broadly applicable and get the same results?
I think that's the practical, language-designy answer. I don't like appealing to the mathematical definition of a function, since that doesn't account for languages like Ruby and Python which presumably wouldn't fall into the original poster's bucket of languages that support "returning multiple values."
And yet, I could (in principle) return a tuple of a different length each time I called a function in either language. This means functions in Python and Ruby are about as far away from the mathematical definition of a function as one can get, so that couldn't be why they don't support multiple return values in the sense that the original poster meant.
Lua is one of the few languages I know which differentiates both syntactically and semantically between "returning a list" and "returning multiple values."
function return_multiple()
return 1,2,3
end
function return_list()
return {1,2,3}
end
a,b,c = return_multiple()
print(a) -- prints out "1"
a,b,c = return_list()
print(a) -- prints out, e.g., "table: 0x7fc991500d20"
Note that I'm using the word "list" where Lua would use the word "table" and using the word "multiple return values" where Lua would use the word "list." That is, in Lua "return 1,2,3" is "returning a list" and "return {1,2,3}" is "returning a table." However, lists aren't values in Lua, i.e., I can't assign a Lua-list to a variable and pass it around, so for clarity's sake I'm using terms that make more sense in non-Lua languages.
The interesting thing about Lua's "multiple return values" is that they almost behave like splatted lists in Ruby — like a chunk of syntax.
function add(a,b)
return a + b
end
function return_multiple()
return 1,2
end
sum = add(return_multiple())
-- sum is now 3
-- add({1,2}) would throw an error, however
In Lua, one can use "unpack" to destructure/splat lists like {1,2,3}, so
sum = add(unpack({1,2}))
would work.
At the end of the day, these approaches all tend to be isomorphic to each other. Given Lua's design considerations (small, fast, easy to move in and out of C, etc.) I'm guessing it makes these distinctions for performance/memory management reasons, but I don't know enough about Lua's internals to say whether that's the actual justification. Outside of that I think Lua's choices are strange since you now have functions which don't return a particular value, but rather these non-syntactic entities called "multiple return values."
Lua's weird return values are basically just exposing the fact that it's a stack-based VM and letting the user take advantage of that. foo(1, return_two_values(arg), 2) pushes 1 onto the stack, pushes arg onto the stack, calls return_two_values (which pops one value from the stack and pushes two new ones), pushes 2 onto the stack, and then calls foo, resulting in foo being called with four arguments.
With this design you get zero-overhead (you save the construction of a table) multiple return values for free, since it simply requires a trivial bit of syntax and no error checking to verify that a function only left zero or one values on the stack. Lists aren't exposed as concrete things that can be passed around because the really aren't things at all.
Actually, foo(1, return_two_values(arg), 2) will call foo with only three values. The , truncates (or extends) the left expression to exactly one value.
Another language that distinguishes between returning a list of values and multiple values is Go. Return variables have to be declared and can be named.
Maybe because the dominant use pattern where return cannot be substituted by output parameters is in expressions.
In other words if there were no expressions then return would not be needed at all.
73 comments
[ 2.8 ms ] story [ 146 ms ] thread[1] https://news.ycombinator.com/item?id=6896378
Content curation is a tried and true technique that some people love. I like reading the SO articles by arstechnica because I don't have to sift through the whole thread _and_ because they are stable, so you know what you link to.
YMMV, but it is definitely more than just copying and excerpt and setting a link, especially as the orginal platform is involved.
http://docs.racket-lang.org/reference/eval-model.html#%28par...
Forth functions (or words, if you insist) can return multiple values as easily as they can return a single value, but the stack metaphor makes this a lot more natural. This is also true of Joy and RPL and other languages which are conceptually organized around mutating a (notional) stack. Multiple return values only become unnatural when you choose an abstraction other than the stack.
I've come across the thought myself from time to time... usually have to end up creating objects/structs to then return, though in the past when I've been lazy (on iOS) I've chunked things into NSArray/NSDictionary.
But darn, I can't remember specific examples right now, I know I've definitely had moments where returning multiple things would have been nice lol.
std::pair<T, boolean> was like a gift from the gods when I found out about it
Modulus calculations like
where a is the remainder modulo n, and b is the residual, so that x = a + b*n.The two outputs from the quadratic formula.
All the matrix factorizations, such as
where A = P L U, and L and U are triangular, and P is a permutation.The remedy of having a data structure to hold the a and b integers above, or the two roots of a quadratic equation, is asinine.
It's exactly like that in Haskell. If it makes sense to return 2 values — return tuple. Works really well with pattern matching. Syntactic overhead = 0.
The persistence of features in programming languages you're describing isn't a cargo cult because the resulting products work. In addition, there's several benefits of conservative language development: it's generally easier to write compilers; existing programmers will find it easier to adopt a language that mostly resembles ones they already know; and some unfashionable but useful features may be retained.
This is more of a "worse is better" situation than a "cargo cult" one.
Assume a language where functions do not only return one value. Now, consider each function in this language. It either returns the same number of values each time, where each has a specific meaning, and they are distinguished either by order or by name. Or it returns an arbitrary number of values, where the semantics of each are the same. But that means the return values are equivalent to a tuple, a dictionary, or an array, which are single values. Therefore we have a contradiction and such a language does not exist. (Yes, I know about values in Lisp and this can be a bit nice. Mostly joking.)
More seriously, ask the question: what relationship between multiple values is useful for returning from functions but not useful enough to be a data structure that can be used in other parts of code?
Semantically I think it's a lot cleaner to make every function 1-in 1-out. Multiple parameters are just a disguise of passing a tuple. In dynamically typed languages, though, it's difficult to make it efficient.
Any metadata about that particular function call.
E.g. function success / effectiveness (did state change?). Runtime. Memory usage.
EDIT: I think co-dependants are still the primary use case, im just suggesting another less obvious use case.
Improves cohesion. Seperates responsibilities. Removes duplication and redundancy.
When you pass the metadata off for aggregation or other processing with this multi return model, you dont pull along a chunk of irrelevant business data at the time.
Sometimes there are pieces of data which are hard to create a cohesive type around. That is, you can compose an new type from other types, but you can't really add any behavior to that new type. This is exemplified by the Tuple type in many languages: it's basically a hack to treat disparate pieces of data as one, and it doesn't offer any way to operate on its own data.
Here's an example from a relatively typical idiom of parsing an int from a string:
The problem here is that TryParse() really returns two values, one of which will be tested to see if the parse was successful, and the other of which is assigned to parseInt. You could test that the string can be parsed and then get the parsed value in two separate functions, but this would be inefficient because you'd essentially have to parse the string twice. I'm on my Mac so I'm not sure I'm remembering this correctly, but I think C# forces you to put the "out" there, which I think is good because it clarifies that parsedInt will be assigned. However, I think there are a number of ways in which the following (hypothetical) redefinition of TryParse (and C# syntax) feels a lot clearer: First of all, the programmer has been forced to assign the success boolean to a clarifying variable. Second, the call has a clearer structure: the input are on the right side of the = and the outputs are on the left.Let's look at some other possible solutions here:
This results in some confusing code. Item1 and Item2 are very poor names for the things they represent. This is a little better, but the creation of a whole new type seems heavyweight, especially given that this new type provides no real functionality. It's tying together two pieces of data which are about to be separated and never used together again (consider, for example, that instead of printing to the console it might return).I guess the argument I'm making here is that just because a function returns to outputs doesn't mean those outputs have a meaningful relationship that would justify having a new type.
If you want to get fancy, you can use the Either monad. This can allow you to say why a parse failed, for example:
In this case, tryParse would have the type: The point here is, you still only return one value, but they can be either of two different kinds of value, as distinguished by being tagged either Left or Right, and can even be different types. Again, one value, no out-of-band signalling.And, of course, Haskell has tuples. You can do interesting things without them, however.
Common Lisp on the other hand, does in fact support multiple return values.
For example, Python's divmod and Lisp's floor are roughly equivalent. But if I say:
>>> x = divmod(11, 5)
x points to the tuple (2, 1).
But if I say:
(setf x (floor 11 5))
x points to the integer 2, though I could have gotten the 1 as well had I used something like multiple-value-bind.
List context works really well with list assignment, which lets you assign multiple return values directly to muliple scalar variables. It also works well with passing multiple return values to the input of another function, of course.
The real answer is "most languages can return multiple values", since whenever structs were introduced. And if you're bugged by the fact that there are multiple input parameters, well, just think of the list of params as a tuple. Which you could picture as anonymous structs anyways.
So that in the end, all functions take one tuple and return one tuple, where tuples can be called structs, classes, or, well, tuples.
The real question being, why is it that there is a syntactic sugar for anonymous input structs but that the sugar for output structs is just being introduced.
And there I have to admit I have no idea why.
The answer to the OP is probably that all computer languages derive from Fortran, and Fortran derived from maths, so it chose f(x, y) as the notation for function application. With that notation, there's no elegant way of handling more return values, and language designers might feel that the extra complexity/ugliness isn't worth it. That, and intellectual inertia.
http://www.lua.org/pil/5.1.html
Ditto for Perl:
I work mostly in C#, and the lack of multiple return values hits me about once a month or so, and I usually have to create a new class just for the purpose of returning two values from one function one time that will never be used again. There's several other possibilities, most of which are even more awkward and annoying - out and ref params, which need some variables declared separately; arrays, lists, and dictionaries, which need either the same type or casting and index by numbers or a string, and tuples, which have strong typing, but name everything Item1, Item2, etc. It might be a good solution if there was support for anonymous functions as return types, but I don't think you can do that right now without using dynamic.
In C#, and I expect Java and most other more statically typed languages, you run into all kinds of awkwardness doing this. Arrays and other data structures are strongly typed by default, and number and type of method returns must be declared. You could return a object[], which is easy enough to declare, but then on the call side, you'd have to declare a object[] to receive the return, then individually cast each element to whatever type it's supposed to be before you can do anything with it. Kinda awkward, and against the spirit of the language.
Declaring multiple returns of different types doesn't seem to help much, either, since you can't declare 2 variables of different types on the same line, so you have to declare them both somewhere else, making it about as awkward as using out params.
The best solution I can think of that fits with the spirit of the language is to use anonymous types. You can already do:
var something = new { Foo = a, Bar = b }; something.Foo.DoStuff(); something.Bar.DoStuff();
In that case, the compiler creates a class for "something" for you invisibly, based on the properties you assigned. What's neat about that is that it maintains strong typing of everything, since it figured out the types from the declaration, so you can still do things with the Foo and Bar properties, and it knows what types they are and enforces all of the standard compile-time type checking.
The downside is that you can't return these anonymous types from a method, as the method return type must normally be statically declared. You could return dynamic, but then you lose all of that static type checking, and are back to a slightly cleaner version of returning object[]. I suppose the language authors figured that it's too complex to return anonymous types from methods, as far as figuring out at compile-time what you're actually calling and what it would return.
And now that I think I've successfully argued myself out of what I originally wanted to do with a ridiculous number of words, I'll just give up.
(Of course you'd have to dump anything beyond that onto the stack!)
I imagine the world would be a lot different (or at least a bit less buggy!) if C had allowed for returning an error code in addition to a return value.
Once you get to higher level languages though, the need sort of falls away. Put data into a container of some type, call it a day.
I'll make the argument that in Haskell, functions BOTH support only a single input value and a single output value. For example, consider the function (+) which takes two numbers and returns their sum. The type of (+) is (+) :: Num a => a -> (a -> a). I have added the parentheses to emphasize the syntax of the type. (+) is a function which takes a single number as input and gives a single function as output!
Now, we can do something like f :: (a,b) -> (x,y,z) and write:
But this isn't really multiple input or return values. We are just inputting or returning a struct (with constructor (,) or (,,), respectively), and we can pattern match against it for the return value.I think that any elegant language should support as few "primitive features" as possible - it should be simple, and let a few powerful ideas (e.g., first-class functions, currying, and pattern matching) let the rest fall out. I think Haskell really embodies this idea.
Python only returns a single value - a tuple. It's just that there is symantic sugar on the functions side to fold multiple values into a tuple, and on the side that's returned to, it's simple value unpacking.
You can validate this in the following way:
The unpacking of tuples into arguments is simply more syntactic sugar, if very useful syntactic sugar.In short, while I love Python, it's still returning just a single value - a tuple, that gives the appearance of returning multiple values.
It's hard to see how this is indistinguishable from returning a list/array/tuple plus supporting list destructuring syntactically, even in a limited way. This works in Ruby, for example:
So, you can have a function which returns an Array and the caller can "act" as if it's returning multiple values of mixed types. Python can do the same thing. Does this count as supporting "multiple return values?"One might think about this mathematically "as if" returning multiple values were the (functional) composition of returning a list and list destructuring. If your language supports lists, you'll always have the ability to return a list, so in a world where one wants to support returning multiple values, why add support for it "directly" when you can add support for something simpler and more broadly applicable and get the same results?
I think that's the practical, language-designy answer. I don't like appealing to the mathematical definition of a function, since that doesn't account for languages like Ruby and Python which presumably wouldn't fall into the original poster's bucket of languages that support "returning multiple values."
And yet, I could (in principle) return a tuple of a different length each time I called a function in either language. This means functions in Python and Ruby are about as far away from the mathematical definition of a function as one can get, so that couldn't be why they don't support multiple return values in the sense that the original poster meant.
Lua is one of the few languages I know which differentiates both syntactically and semantically between "returning a list" and "returning multiple values."
Note that I'm using the word "list" where Lua would use the word "table" and using the word "multiple return values" where Lua would use the word "list." That is, in Lua "return 1,2,3" is "returning a list" and "return {1,2,3}" is "returning a table." However, lists aren't values in Lua, i.e., I can't assign a Lua-list to a variable and pass it around, so for clarity's sake I'm using terms that make more sense in non-Lua languages.The interesting thing about Lua's "multiple return values" is that they almost behave like splatted lists in Ruby — like a chunk of syntax.
In Lua, one can use "unpack" to destructure/splat lists like {1,2,3}, so would work.At the end of the day, these approaches all tend to be isomorphic to each other. Given Lua's design considerations (small, fast, easy to move in and out of C, etc.) I'm guessing it makes these distinctions for performance/memory management reasons, but I don't know enough about Lua's internals to say whether that's the actual justification. Outside of that I think Lua's choices are strange since you now have functions which don't return a particular value, but rather these non-syntactic entities called "multiple return values."
With this design you get zero-overhead (you save the construction of a table) multiple return values for free, since it simply requires a trivial bit of syntax and no error checking to verify that a function only left zero or one values on the stack. Lists aren't exposed as concrete things that can be passed around because the really aren't things at all.