Path: utzoo!utgpu!news-server.csri.toronto.edu!rpi!zaphod.mps.ohio-state.edu!pacific.mps.ohio-state.edu!linac!att!ucbvax!bloom-beacon!dont-send-mail-to-path-lines From: gyro@cymbal.reasoning.COM (Scott Layson Burson) Newsgroups: comp.lang.scheme Subject: Multiple return values Message-ID: <9104022333.AA00572@cymbal.reasoning.com.> Date: 2 Apr 91 23:33:38 GMT References: <1991Apr1.181633.12561@snitor.uucp> Sender: daemon@athena.mit.edu (Mr Background) Reply-To: Gyro@reasoning.com Organization: The Internet Lines: 86 Date: Mon, 1 Apr 1991 18:16:33 GMT From: Doug Moen In the latest issue of LISP Pointers, Pavel Curtis (Pavel@Xerox.Com) discusses the Scheme multiple return value proposal. [...] call-with-values is rather inconvenient to use directly; some sort of syntactic sugar is needed. Curtis describes and rejects a new form 'bind-values', which is similar to muliple-value-bind in Common Lisp. He then describes a better solution: 'We are thus considering allowing a list of variables to appear in place of a single one in let and let* expressions: (let* ((a (foo)) (b (bar a)) ((c d) (baz a b)) (e (mumble a b c d))) (frotz a b c d e)) I have been using a slightly different syntax for years, e.g.: (let ((a b c (foo))) ...) I am very fond of this syntax. It has one fewer pair of parens than the one proposed, and also doesn't discriminate visually between the 1-value case and and the >1-value case -- some might find this a bug, but in a program full of multiple values I find it a feature. I have macros that implement this in Common Lisp and T. (Actually the syntax they implement contains an additional extension, which again I like a lot but I don't know if I would make a serious proposal of. The idea is that the order in which evaluation and binding are performed is indicated by depth of nesting of clauses, so that, e.g.: (let ((a b (foo)) ((c d e (bar a b)) ((f (zot b c e)))) (m n o (quux))) ...) is equivalent to (let ((a b (foo)) (m n o (quux))) (let ((c d e (bar a b))) (let ((f (zot b c e))) ...))) The idea here is that all clauses at a given depth are performed in parallel, and all clauses at depth n are done before/outside of all clauses at depth >n. I like this as it allows me essentially to mix the effects of LET and LET*, and also lets me supply something of a visual indication of the data flow (the way the example is written, for instance, is intended to convey that C, D, E, and F do not depend on M, N, and O, though this is only a convention, NOT a restriction enforced by the implementation).) Anyhow, maybe this latter preference of mine is a bit idiosyncratic, but I think the first proposal is something most everyone would like. I have a counter-proposal. I feel there is a much simpler way to support multiple return values; one which fits in better with the rest of the language: multiple return values are represented by lists. [...] I like to write in a style that makes liberal use of multiple values. I would be discouraged from doing so on efficiency considerations were they to be implemented as lists. I also agree with Pavel that there is a stylistic difference in the way the two are used. Consider the situation in C, where you can return several values from a function by packaging them up into a struct. I feel that if I have to declare a struct type solely for the benefit of the return value of a single function, that is more like "multiple values" than it is like a structure. Conversely, if that struct type is in use in many places already, then it would often make sense (in the Scheme case) to return it as a list, because much of the time I'm going to be manipulating the list as a unit rather than destructuring it (since there are already other functions that take lists like that as arguments). -- Scott