Path: utzoo!utgpu!jarvis.csri.toronto.edu!rutgers!apple!sun-barr!newstop!sun!quintus!pds From: pds@quintus.UUCP (Peter Schachte) Newsgroups: comp.lang.misc Subject: Re: Language Tenets (too long) Message-ID: <1223@quintus.UUCP> Date: 26 Jul 89 23:32:56 GMT References: <57125@linus.UUCP> <1989Jun24.230056.27774@utzoo.uucp> <1207@quintus.UUCP> <1406@l.cc.purdue.edu> <1989Jul17.184707.415@maths.nott.ac.uk> Reply-To: pds@quintus.UUCP (Peter Schachte) Organization: Quintus Computer Systems, Inc. Lines: 98 In article <1989Jul17.184707.415@maths.nott.ac.uk> anw@maths.nott.ac.uk (Dr A. N. Walker) writes: > I might want to write > records[i++] errcount <- write(fd,buf,BIGBSIZE)/BSIZE >after which > records[i++] = write(fd,buf,BIGBSIZE)/BSIZE; > errcount = write(fd,buf,BIGBSIZE)%BSIZE; >is erroneous and > { int temp = write(fd,buf,BIGBSIZE); > records[i++] = temp / BSIZE; > errcount = temp % BSIZE; } >is becoming gross (and much harder to optimise). Absolutely. But how about: divrem(write(fd,buf,BIGBSIZE), BSIZE, &records[i++], &errcount); It is essentially the same as your multiple return example, and doesn't have the same perils. It does have the flaw that errcount can't be a register variable. It is conceivable, though, that a global optimizer could put errcount into a register. The problem with multiple returns is filling out the semantics. As I see it, there are two basic ways to handle this: 1. multiple results are packed up into a single structure to be returned. To complete the semantics of this, you only need to specify the semantics of passing such a structure as argument to a function (or primitive like +). One sensible solution is to consider the first of the multiple results to be passed as argument, and the remaining results to be "passed around" the function. For example, if /% returns a quotient and remainder as values, and + returns one value, then: (x/%y)+z would return two values: x/y+z and x%y. I think this semantics could be made to work. I don't really think it's very useful, though. The problem is that usually, when you have multiple results, you want to do different things with them. In order to do that with this sort of multiple values, you have to assign them to separate variables. If you're going to do that anyway, why not just write functions that take pointers indicating where to store the results, as I showed above? 2. The other approach is to treat multiple results as separate things. Forth, Pop-2, and CommonLisp do this. Forth and Pop-2 store results, as well as arguments, on a stack. This gives them great flexibility with multiple results; in effect, multiple results are handled just like a single result. CommonLisp is a bit less flexible*. I am a bit skeptical of Pop-2's approach: foo(divrem(x,y)) (where divrem returns both quotient and remainder, and foo takes two arguments) calls foo with x/y and x%m as its two arguments. It may be pure prejudice, but I'm uncomfortable having two arguments to a function come from the same expression. In any case, it's not terribly useful, since there's a good chance I'll want the arguments in the other order, or I'll want another argument between them, or something. I belive Pop-2 does provide stack manipulation primitives, so this can be handled, but it's going to look pretty grungy. (The same arguments apply to Forth, except that Forth doesn't have the expression notation. This sort of thing is the way one programs in Forth, so this kind of code looks no different than any other Forth code.) It seems to me that the cleanest way to handle multiple results is to just always put them into variables. And this is better done by passing pointers to where to put the results than by muddling the semantics of expressions with multiple returns. Or alternatively, go to a pure stack dicipline, where you always manipulate the stack to get the result(s) from some invocations into others. ---------------- * CommonLisp has 5 forms for handling multiple returns, but none of them allow you to get multiple results from one function call into different function calls without putting them into variables first. For example, suppose CommonLisp had a divrem function, and suppose I wanted to compute x/y*10+log(x%y). I don't see how to do this conveniently without putting x/y and x%y into temporary variables. Maybe I'm just missing it. This is not a condemnation of CommonLisp. Since CommonLisp does not have VAR parameters (to functions) like Pascal or an address-of operator like C, returning multiple values and putting them into variables is the most sensible way to handle multiple returns. -- -Peter Schachte pds@quintus.uucp ...!sun!quintus!pds