Article View: comp.lang.misc
Article #350Re: Language Tenets (too long)
From: Peter Schachte
Date: Wed, 26 Jul 1989 23:32
Date: Wed, 26 Jul 1989 23:32
98 lines
5034 bytes
5034 bytes
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
Technical Details
Message-ID:
<1223@quintus.UUCP>Path:
arc1-ca.pugleaf.net!utzoo!utgpu!jarvis.csri.toronto.edu!rutgers!apple!sun-barr!newstop!sun!quintus!pdsReferences:
<57125@linus.UUCP> <1989Jun24.230056.27774@utzoo.uucp> <1207@quintus.UUCP> <1406@l.cc.purdue.edu> <1989Jul17.184707.415@maths.nott.ac.uk>Show Full Headers
Complete Article Headers
Path: arc1-ca.pugleaf.net!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