Path: utzoo!utgpu!news-server.csri.toronto.edu!rpi!zaphod.mps.ohio-state.edu!sdd.hp.com!hplabs!otter.hpl.hp.com!hpltoad!cdollin!kers From: kers@hplb.hpl.hp.com (Chris Dollin) Newsgroups: comp.lang.scheme Subject: Re: Multiple return values Message-ID: Date: 5 Apr 91 08:54:19 GMT References: <9104031856.AA27280@kuwait> Sender: news@hplb.hpl.hp.com (Usenet News Administrator) Organization: Hewlett-Packard Laboratories, Bristol, UK. Lines: 55 In-Reply-To: jonl%kuwait@lucid.COM's message of 3 Apr 91 18:56:19 GMT Nntp-Posting-Host: cdollin.hpl.hp.com It's interesting to watch this discussion develop. I have long detested the cack-handed way Common Lisp handles multiple values; this is, of course, because I have used a language which has handled multiple values since its inception, rather than having them grafted on at a later stage. That language is Pop11 (descended from Pop2). Now, it is clear that the way Pop handles multiple values (see shortly) is, as it stands, entirely unsuitable for Scheme; but insights from their use may be applicable. I'll try to leave my comments as unbiased as possible. Unlike CL, Pop multiple values can appear in any context; if a function returns multiple results, then the caller must be prepared to deal with them. This means that one cannot just extend an existing function with an extra result and expect old code to continue working. In practice, this does not seem to have many bad consequences; the addition of a single new name to the namespace (the new version of the function), with the ``old'' function being redefined as one which calls the new function and discards the result, is sufficient. Of course, if this happens several times, you may have to restructure your code, if you don't like the plethora of new names. However, there's more. As a consequence of the way multiple values are defined, (and of the way they're implemented), *multiple values accumulate*. Suppose that F takes one argument and delivers two results, G ditto, and H requires four arguments. Then (H (F x) (G y)) is sensible and applies H to the quartet of values returned by F and G. Someone discussed what would happen with BEGIN. An alternative not mentioned is that (BEGIN E1 ... En) would return *all* the results of the Ei (hmm ... just like a sequential version of VALUES). One might want to add functions to control this possible explosion of values: NONE (takes arbitrary number of args, no results), INITIAL (takes non-zero number of args, returns first), FINAL (non-zero number of args, returns last). This approach has the possible disadvantage that it is no longer possible to define functions that return ``possibly useful'' results that will be quietly discarded if used in a no-value context; again, experience in Pop suggests that this is not a problem. [Why did I say Pop's multiple values are unsuitable for Scheme? Because they are implemented by simply using a stack, and making it visible to the programmer. There is *no* special checking for number-of-arguments-passed or number-of-results-returned; if F is defined as, say, add-1, then (F 1 2) returns multiple values, viz, (1 3). Conversely, if G expects two arguments, and delivers (eg) their sum, then (F 2 (G 3)) delivers 6. The surprising thing is that this free-wheeling approach to arity results in few errors, most of which are detected very quickly (stack underflow is, of course, checked for). However, I do not see this as a sensible change of approach for Scheme; it would make more sense in this context to keep arity-checking for calls.] -- Regards, Kers. | "You're better off not dreaming of the things to come; Caravan: | Dreams are always ending far too soon."