[comp.lang.c] proposals

brnstnd@stealth.acf.nyu.edu (04/09/90)

In article <16390@haddock.ima.isc.com> karl@haddock.ima.isc.com (Karl Heuer) writes:
> I think that if it's worth fixing, it's worth fixing right: invent a notation
> that will allow each of `i = -i', `b = !b', `u = ~u', `p = p->name' to be
> expressed without uttering the LHS more than once.  I think the best you can
> do without totally destroying the language is to add a pronoun `it', which,
> within the RHS of an assignment expression, denotes the original value of the
> target.  This would also allow things like `x[i++] = 1.0 - it'.

I was planning to wait for the next round of Q design in comp.lang.misc
to talk about this, but a C compiler now could easily include these
features, so here goes.

Algebraic notation expresses tree expressions. The problem here is to
find a good notation for directed acyclic graph expressions, where a
node may be used in more than one parent expression. Of course, this is
equivalent to declaring variables local to an expression.

Here's the best solution I've come up with: `foo=expr1(expr2). This
evaluates expr1 exactly once, and uses the value in expr2 wherever foo
appears. (Actually, expr1 is evaluated at its first use in expr2, or as
bounded from there by sequence points.) The notation is actually more
general: `foo=expr1`bar=expr2`tch=expr3(expr4) is valid, and means to
evaluate expr{1,2,3}, place them into {foo,bar,tch}, and then substitute
them inside expr4 (again, not necessarily in that order). You can regard
foo as a local variable, with type implicitly determined by expr1.

Some examples: i = -i could be written `neg=&i(*neg=-*neg). Or macros:

#define NEGATE(x) (`neg = &(x)(*neg = -*neg))
#define BACKWARDS(a,b) (`el = (a)`ef = (b)(ef,el,ef)) /* evals b first */

BACKWARDS(a,b) is like (a,b) but evaluates b first; it's impossible to
write in straight C (at least without some function call trickery).

#define swap(x,y) (`p1 = (x)`p2 = (y)(`temp = *p1(*p1 = *p2,*p2 = temp)))
#define SWAP(x,y) (swap(&(x),&(y))) /* SWAP lvalues, swap pointers */

Here swap(&foo,&bar) swaps the values in foo and bar, no matter what
their type; it returns the original value of foo (now bar). There's
absolutely no possibility of namespace conflict; a good compiler might
produce a warning if p1, p2, or temp were declared elsewhere, but the
swap macro would still work. And each argument is evaluated just once.

The advantage of `() over block expressions is that it's so easy to
declare variables; in fact, `() seems to make typeof() rather useless. 
The disadvantage is that block expressions use a more familiar form, and
their explicit typing of local variables helps detect probable errors
like swap(x,n) with float x; int n. Block expressions also allow loops,
and they're available in at least one compiler (gcc).

So, Karl, whaddya think? Would `() be a useful addition to C?

---Dan