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