[comp.lang.misc] The need for D-scussion

cik@l.cc.purdue.edu (Herman Rubin) (03/22/88)

In article <3073@haddock.ISC.COM>, karl@haddock.ISC.COM (Karl Heuer) writes:
> In article <27143@linus.UUCP> bs@gauss.UUCP (Robert D. Silverman) writes:
> >I am a computational number theorist who writes a LOT of code requiring that:
> >A*B/C [and] A*B%C be computed where A,B,C are all 30 bit quantities.  The
> >difficulty is that even though the algorithm guarantees that the results of
> >the computations fit in 30 bits, the product A*B may not. I therefore need to
> >make extensive use of any 'emul' and 'ediv' facilities that a computer may
> >have. ... Machines which have such instructions should, In my opinion,
> >generate emul/ediv code whenever it sees A*B/C and only return a run-time
> >arithmetic overflow if the quotient doesn't fit in the appropriate word-size.

I think Bob has oversimplified slightly and not asked for enough.  What I would
like to see is something like

	u,v = a*b///c

(or however he would like to write it; maybe eventually it would become
standardized, but it is not now).  What a reasonable language needs is the
ability of the user to define types and operations at will.  C++ allows the
introduction of types in some, but not all situations; it does not allow the
introduction of operators.

> Such a special case would be a wart in the language.  The "correct" way to do
> this is to provide an "lmuldiv" function which has the desired semantics (I'd
> have it return an ldiv_t structure, since it already exists in ANSI C), and
> encourage vendors to give their compilers the ability to inline it (along with
> other trivial functions, such as abs()).

This is precisely what has made it difficult for mathematicians, and all who
understand the computer, to make reasonable use of it.  To follow the desire
of the Mikado to "make the punishment fit the crime," I would sentence all 
those who would deny the right to use infix notation to others the right to
use it for themselves.  It is the use of prefix rather than infix notation
which makes assembler programming such a chore in 99% of the assemblers.

Furthermore, returning a list of values for a function is far different from
returning a structure.  In the case above, it is likely that everything
should be in registers.  And it takes no longer to produce the efficient
code with a reasonable language than it does to produce the less efficient
code with the "warts" removed.  In fact, it takes much less time to write
a reasonable notation.  It takes less time to read someone's reasonable infix
notation, even if that is not the way I would write it, than prefix notation,
if I have any idea of what is being done.

As long as programmers are taught to think in terms of a language, rather
than the machine, it will be difficult to get vendors to allow the forcing
of inline.

-- 
Herman Rubin, Dept. of Statistics, Purdue Univ., West Lafayette IN47907
Phone: (317)494-6054
hrubin@l.cc.purdue.edu (ARPA or UUCP) or hrubin@purccvm.bitnet

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

In article <719@l.cc.purdue.edu> cik@l.cc.purdue.edu (Herman Rubin) writes:
>This is precisely what has made it difficult for mathematicians, and all who
>understand the computer, to make reasonable use of it.  To follow the desire
>of the Mikado to "make the punishment fit the crime," I would sentence all 
>those who would deny the right to use infix notation to others the right to
>use it for themselves.  It is the use of prefix rather than infix notation
>which makes assembler programming such a chore in 99% of the assemblers.

You must really hate Lisp, and Forth, and RPN calculators, and . . . .

>Furthermore, returning a list of values for a function is far different from
>returning a structure.

If so, the compiler should be improved.  There is no theoretical difference
(unless you allow variable length lists, but that is not what people were
talking about).

>As long as programmers are taught to think in terms of a language, rather
>than the machine, it will be difficult to get vendors to allow the forcing
>of inline.

As long as programmers are taught to think in terms of a machine,
rather than the language, it will be difficult to get portable code
that can be moved to that 1 teraflop computer that will come out
tomorrow, then to the 10 teraflop computer that will come out the day
after, and then to the 100 teraflop computer that will come out a week
from Monday.

(When someone finally builds the Ultimate Computer, the one that
uses infinite parallelism and quantum effects to achieve the fastest
operation that can ever exist, *then* I will give in on this argument.)
-- 
In-Real-Life: Chris Torek, Univ of MD Comp Sci Dept (+1 301 454 7163)
Domain:	chris@mimsy.umd.edu	Path:	uunet!mimsy!chris

shebs%defun.utah.edu.uucp@utah-cs.UUCP (Stanley T. Shebs) (03/23/88)

In article <719@l.cc.purdue.edu> cik@l.cc.purdue.edu (Herman Rubin) writes:

>[...] It is the use of prefix rather than infix notation
>which makes assembler programming such a chore in 99% of the assemblers.

Gee, and I thought it was the explicit management of registers and memory
that made assembly programming such a chore!  CAL (Cray Assembly Language)
is infix, but I hadn't noticed that it made much difference to anybody.

In case anybody hadn't realized it, this is the same Herman Rubin that's
been calling for "portable assembly languages" for years.  The suggestion
that such a desire is self-contradictory doesn't seem to bother him.
The suggestion that he should try doing this himself is met with a request
for money upfront, with no concrete evidence that the activity would be
useful.  He still doesn't seem to have consulted the literature - reading
a CACM from, say, 1965 is very educational, particularly if you still have
dreams of a "high-level language that allows the programmer to exploit
special machine instructions".  A language like C didn't get designed in
a vacuum, you know - "systems programming languages" was an intensely
studied area in the late 60s, and C just happened to be the winner of those
long-ago battles...

							stan shebs
							shebs@cs.utah.edu

karl@haddock.ISC.COM (Karl Heuer) (03/26/88)

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

Or perhaps the language should be improved.  In C, the div() function returns
a struct.  If I want to add the squares of the two components, I have to write
either
  qr = div(x, y);
  z = qr.quot * qr.quot + qr.rem * qr.rem;
or use a function
  int f(struct div_t qr) { return (qr.quot * qr.quot + qr.rem * qr.rem); }
  z = f(div(x, y));
The former requires a throwaway variable; the latter, a throwaway function.

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

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.

I don't know if this is what Herman was talking about, but in this sense the
current C model is lacking.  Whether this could be "fixed" in a C-like
language is another question.

Karl W. Z. Heuer (ima!haddock!karl or karl@haddock.isc.com), The Walking Lint

cik@l.cc.purdue.edu (Herman Rubin) (03/27/88)

In article <3177@haddock.ISC.COM>, karl@haddock.ISC.COM (Karl Heuer) writes:
> In article <10763@mimsy.UUCP> chris@mimsy.UUCP (Chris Torek) writes:
> >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.
> >
> >If so, the compiler should be improved.  There is no theoretical difference.

If so, there is at least confusion.  As I read K&R, a struct is a memory
assignment.  In some cases the memory assignment can be transferred to the
register file.  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.  One item can be a register, another a byte
local to the program, another an external float, we may possibly have both
local and external arrays, etc.

Generalizing the K&R struct cannot solve the problem.  If an external is to be
in the object, we have the problem of multiple definition.  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.  If we want to use the 
x.y struct notation and have the list expanded, we can easily do it with a
#define statement, but the other way is hard to do.  We are dealing with
different constructs.

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

In Lisp, the language certainly suggests that at some time there is a real
machine object called qr.  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).  I am not saying that the user must
not set up the suggested notation, rather that he need not.

The Forth example requires that the stack exist.  I think that this may
make it extremely difficult for a compiler to "do what is natural."  It is
likely that the "natural" thing to do is far more efficient also.

> 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.
> 
> I don't know if this is what Herman was talking about, but in this sense the
> current C model is lacking.  Whether this could be "fixed" in a C-like
> language is another question.

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?  I doubt that
the notation

	q,r = a _div_ b

will confuse a human reader of this article.  Whether we have, by ignoring 
this problem in the past, messed up our current compilers so that it is
necessary to do a complete rewriting rather than a fix is another matter.

> Karl W. Z. Heuer (ima!haddock!karl or karl@haddock.isc.com), The Walking Lint


-- 
Herman Rubin, Dept. of Statistics, Purdue Univ., West Lafayette IN47907
Phone: (317)494-6054
hrubin@l.cc.purdue.edu (ARPA or UUCP) or hrubin@purccvm.bitnet

barmar@think.COM (Barry Margolin) (03/28/88)

In article <3177@haddock.ISC.COM> karl@haddock.ima.isc.com (Karl Heuer) writes:
>In article <10763@mimsy.UUCP> chris@mimsy.UUCP (Chris Torek) writes:
>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)))

You're behind the times in your Lisp knowledge.  Common Lisp, and
Zetalisp before it, has functions with true multiple values.  The
above would be written

(setq z (multiple-value-bind (quotient remainder)
	    (floor x y)
	  (+ (* quotient quotient) (* remainder remainder))))

Barry Margolin
Thinking Machines Corp.

barmar@think.com
uunet!think!barmar

kers@otter.hple.hp.com (Christopher Dollin) (03/28/88)

"barmar@think.COM (Barry Margolin)" says:

|You're behind the times in your Lisp knowledge.  Common Lisp, and
|Zetalisp before it, has functions with true multiple values.  The
                                        ^^^^
|above would be written

"true" multiple values? When most of the good bits have been taken away? [Is
white bread "true" with respect to brown?] The only justification I can see for
the feebleness of Common Lisp's "multiple" values is that it's a little easier
to describe the types of functions over them.

Sorry to sound so anguished. It's just that Common Lisp's multiple values seem
to give you so little when you come from a language such as Pop11 where the
open stack makes them so easy to use and opens up a host of effective idioms.
[Yes, you can be bitten, just as you can with VL's implicit supply of NIL's.
Yes, describing the types is a little harder. I think it's worth it.]

Regards,
Kers                                    | "Why Lisp if you can talk Poperly?"

kers@otter.hple.hp.com (Christopher Dollin) (03/28/88)

Sorry, when I said

| ... The only justification ... feebleness of CL's "multiple" values ...

I was forgetting efficiency. Or was I?

Regards,
Kers                                    | "Why Lisp if you can talk Poperly?"

gaynor@porthos.rutgers.edu (Silver) (03/29/88)

barmar@think.COM (Barry Margolin) writes:
> You're behind the times in your Lisp knowledge.  Common Lisp, and
> Zetalisp before it, has functions with true multiple values.  The
> above would be written
>
> (setq z (multiple-value-bind (quotient remainder)
> 	      (floor x y)
> 	    (+ (* quotient quotient) (* remainder remainder))))

I too am behind the times in my knowledge of Lisp.  How would Scheme's
continuations fit into the area of multiple return values?

Regards,
[Ag]

barmar@think.COM (Barry Margolin) (03/30/88)

In article <Mar.28.12.43.35.1988.1511@porthos.rutgers.edu> gaynor@porthos.rutgers.edu (Silver) writes:
>barmar@think.COM (Barry Margolin) writes:
>> (setq z (multiple-value-bind (quotient remainder)
>> 	      (floor x y)
>> 	    (+ (* quotient quotient) (* remainder remainder))))
>  How would Scheme's
>continuations fit into the area of multiple return values?

Continuations would have to be extended to be able to take multiple
arguments.  In order to precisely duplicate Common Lisp multiple-value
semantics, the above MULTIPLE-VALUE-BIND would call FLOOR with a
continuation of

(lambda (continuation &optional quotient remainder &rest ignore)
  (continuation (+ (* quotient quotient) (* remainder remainder))))

(I'm using CL lambda-list syntax because I'm not very familiar with
Scheme syntax).  This duplicates the feature of allowing the function
to return a different number of values than those explicitly
requested, where extra values are ignored and values not provided are
defaulted to NIL.

(values ...) is then equivalent to (continuation ...) and (values-list
list) is (apply continuation list).

Converting the rest of the multiple-value forms is similarly
straightforward.

Barry Margolin
Thinking Machines Corp.

barmar@think.com
uunet!think!barmar