chris@umcp-cs.UUCP (Chris Torek) (05/23/86)
In article <1482@mmintl.UUCP> franka@mmintl.UUCP (Frank Adams) writes: >In article <825@bentley.UUCP> kwh@bentley.UUCP writes: >>In article <1455@mmintl.UUCP> franka@mmintl.UUCP (Frank Adams) writes: >>>... Supposing that "$" is being used for this ["multi-assignment"] operator, >>>then to set both "a" and "b" to zero, one would write "a $ b = 0", rather >>>than "a = b = 0", as C does.... >> >>What do you mean by this? I don't see how this operator allows you to do >>anything that simple assignment doesn't. Examples? > >Well, in C it doesn't, since C supports call by value only. True but misleading: one gets the effect of call-by-reference by passing the value of the address of a variable. The called routine then determines whether the effect is more like call- by-reference or like value-result. *I* think this is the `right' way to do it; I dislike the `Pascal effect': { near the top of a ~20000 line program: } procedure gorf(var p : TablePtr); ... { many pages of code later: } tp := p1; gorf(tp); tp := p1; { why is this here? } That is, there is no way to tell at the point of call that a given procedure or function may modify one or more of its arguments. In C this is immediately obvious: tp = p1; gorf(&tp); tp = p1; /* since gorf could clobber tp */ Anyway, back to the main issue: >With a "$" operator [and call-by-reference], one could then write >something like "getlin(fp, buff, buflen, actlen$lenread);"; >without it, one must use a separate assignment. True. I have never used a language that will do something like this. I am curious about how such a language would treat aliasing problems. Suppose I have the following (beware, random source language mix): procedure ugly options(main); type ty = array [1..3] of integer; var i, w, z : ty; procedure tricky(in out a, b : ty); begin a[i[1]] := 3; i[1] := 2; b[2] := a[i[1]] + 2 end; begin i[1] := 1; tricky(w $ i, i $ z) end. Now if the language is implemented using call-by-reference with a `hidden' assignment afterwards, it behaves differently than if it is implemented using `thunks' and call-by-name (which is the method that sprang to my mind upon seeing the original example). I think the aliasing problems are bad enough when all aliasing is explicit, as in C (I have to take an address of a non-heap variable, or copy a pointer variable, to create an alias). However, the ability to create aliases is useful, and I think the Pascal method of keeping non-heap variables `pure' (but watch those call-by-references!) is too limiting: /* * Build a linked list such that the first thing entered * into it is also at the head of the list. */ struct list * buildlist() { register struct list *p, **np; struct list *top; extern struct list *getitem(); np = ⊤ while ((p = getitem()) != NULL) { *np = p; np = &(*np)->next; } *np = NULL; return (top); } This routine is more complex if one is unable to alter `top' in this way: function buildlist : listptr; var head, cur, p : listptr; begin head := nil; p := getitem; while p <> nil do begin if head <> nil then cur^.next := p else head := p; cur := p; p := getitem end; if head <> nil then cur^.next := nil; buildlist := head end; Even ignoring the extra `getitem', the two `if' tests are ugly. But I have digressed again. I think I should vote against a `multiple assignment' operator, given a choice. It seems to me to add only a bit of functionality at the cost of a lot of complexity. -- In-Real-Life: Chris Torek, Univ of MD Comp Sci Dept (+1 301 454 1516) UUCP: seismo!umcp-cs!chris CSNet: chris@umcp-cs ARPA: chris@mimsy.umd.edu