5 ms·
A proof by contradiction: Assume a language where functions do not only return one value. Now, consider each function in this language. It either returns the s
by asolove 13y ago
A proof by contradiction:
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?
- deleted 13y ago[deleted]
- plorkyeran 13y agoThe same argument applies to functions with multiple parameters, and yet most languages support multiple arguments rather than requiring one to use tuples.
- zanny 13y agoThough to some degree when you consider, say, python, the call syntax foo(x,y) and a tuple (x,y) look very similar, and behave like a map.
- deleted 13y ago[deleted]
- cafard 13y agoFor 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.
- asolove 13y agoBut, 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.)
- shiro 13y agoReturning 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.
- CraigJPerry 13y ago>> 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.
- asolove 13y agoWhy 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.
- CraigJPerry 13y agoWhy 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.
- kerkeslager 13y ago> 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.
- deleted 13y ago[deleted]