[comp.lang.c] multiple valued functions

chris@mimsy.UUCP (Chris Torek) (03/28/88)

>>>In article <719@l.cc.purdue.edu> cik@l.cc.purdue.edu (Herman Rubin) writes:
>>>>Furthermore, returning a list of values for a function is far different from
>>>>returning a structure.

>>In article <10763@mimsy.UUCP> chris@mimsy.UUCP (Chris Torek) writes:
>>>If so, the compiler should be improved.  There is no theoretical difference.

In article <727@l.cc.purdue.edu> cik@l.cc.purdue.edu (Herman Rubin) writes:
>If so, there is at least confusion.  As I read K&R, a struct is a memory
>assignment.

If this means `an ordered sequence of objects that are stored in
memory from ``low'' addresses to ``high'' addresses', I will call
that a fair description of a C structure.  (Note, however, that
not everything in every C structure is addressible.  Bitfields are
particularly nasty.)

>In some cases the memory assignment can be transferred to the
>register file.

Basically, whenever the compiler is sure the members of a structure
are unaliased, and that they fit into the registers.  (Note that in
C, function return values are always unaliased.)

>A list consists of items each of which has its own location.
>It does not convey the impression that the locations of the items in the list
>have any relation to each other.

I.e., the ordering is removed.

>Generalizing the K&R struct cannot solve the problem.

With this I disagree.  A dynamic structure (really generalised aggregate)
builder and exploder in the language mean that ...

>If an external is to be in the object, we have the problem of
>multiple definition.

one could say, e.g.,

	register remainder;
	extern int quotient;

	{ quotient, remainder } <- a div b;	// or whatever the syntax is

>Furthermore, if I use the same type of list several times, with
>different arguments each time, it is merely necessary to type in
>the relative arguments.

Could you clarify this?  I do not see what you intend.

>In article <3177@haddock.ISC.COM> karl@haddock.ISC.COM (Karl Heuer) writes:
>>Or perhaps the language should be improved.  In C, the div() function returns
>>a struct.   .....
>>In Lisp, you're still returning an aggregate.  Things are a little better,
>>because you can tighten the scope:
>>  (setq z
>>        ((lambda (qr) (+ (* (car qr) (car qr)) (* (cdr qr) (cdr qr))))
>>         (div x y)))

>In Lisp, the language certainly suggests that at some time there is a real
>machine object called qr.

(Compilers are good at removing unneeded objects, if only because old
languages force this sort of notation.)

>The way I am proposing the list, this is never more than a virtual
>object, and does not need a name.  However, the user assigns names
>to the elements of the list, and refers to them, rather than
>having to write (car qr) and (cdr qr).

You can do this in Lisp.  The name of the operation will depend on your
system, but it will look something like

	(bind (q r) (div x y) (+ (* q q) (* r r)))

---that is, for each name in the first list, bind it to the next
value from the second list; when all names have been bound, evaluate
the remaining expressions.  The normal lambda binding form is
 ((name1 value1) (name2 value2) ... (nameN valueN)) rather than
 ((name1 ... nameN) (value1 ... valueN)), but either is easy.
I still find this notation somewhat awkward.

>>In Forth, you can actually return multiple values (as opposed to returning a
>>single value of aggregate type):
>>  x @ y @ div  dup *  swap dup *  +  z !

>The Forth example requires that the stack exist.

Not really; but again, the `compiler' has to work hard to discover
that it need not be used.

>>There's a certain elegance here which is lacking in the first two.  The qr
>>temporary has been absorbed by the syntax of the language, in exactly the same
>>manner as the temporary results of the "*" operator in all three examples.

>Too much elegance, and not enough simplicity.  Both versions are unnecessarily
>complicated.  From the standpoint of a computer language, how can there be any
>difficulty in allowing operators or procedures to produce lists?

There is not.

>I doubt that the notation
>
>	q,r = a _div_ b
>
>will confuse a human reader of this article.

The Xerox langauge Mesa has this sort of notation.  One can,
and often does, write

	[q, r] _ foo[a, b]	-- `_' represents a left-pointing arrow

How does it work?  Why, `foo' takes one structure and produces
one structure.  [a, b] takes any two random variables and
constructs the argument structure; [q, r] takes any return
structure and splits it into two random variables.  If `div'
were a builtin operator that returned the [q,r] pair, even a
Vax Mesa compiler as weak as 4BSD Vax PCC could compile this to

	# put the arguments in registers, because the structure
	# made of one quad and one long fits there entirely
	movl	a,r0
	clrl	r1			# presuming a is unsigned
	movl	b,r2
	# `call' the function
	ediv	r0,r2,r0,r1		# if I got the order right
	# its `return value' is a structure that is a pair of longs
	# and is therefore in r0 and r1
	movl	r0,q
	movl	r1,r

which, fed through any peephole optimiser, becomes

	movl	a,r0
	clrl	r1
	ediv	r0,b,q,r		# or is it ediv r0,b,r,q?

which is, as far as I know, the best you can do if you intend
to use ediv.  (Actually, I suspect this way goes faster:

	divl3	a,b,q
	mull3	b,q,r0
	subl3	r0,a,r1

ediv is very slow.  One would do this for signed division, and
use ediv only for unsigned.  [Mesa has signed and unsigned types,
although I cheated a bit, as it does not have quad length types.])
-- 
In-Real-Life: Chris Torek, Univ of MD Comp Sci Dept (+1 301 454 7163)
Domain:	chris@mimsy.umd.edu	Path:	uunet!mimsy!chris