eric@snark.UUCP (Eric S. Raymond) (01/05/89)
In article <9310@ihlpb.ATT.COM> nevin1@ihlpb.UUCP (55528-Liber,N.J.) writes: >This (using expression forms) won't work too well in (full) C. The problem is >that pure expression-based languages (like LISP) tend to be typeless as well. >Having to return a specific data type severely limits the usefulness of making >control-flow constructs (if, switch, for, etc.) expression-oriented. To see that this is false, try a simple thought experiment. Imagine that you have modified your C compiler so that the language now has two new properties; 1. Every block contruct { <st1>; <st2>; .... <stn> ;} returns, as an assignable rvalue, the value of the nth statement <stn>. 2. The for, while, do, and case constructs return the value of the last block executed before termination; that is, the value of the last *statement* executed before termination. Voila! Expression-oriented C. Trivial to implement, and *incredibly* useful (if you've ever written LISP you know why). Look at what we could *drop* from the language -- the sequential-execution comma and ?: operators, for starters. If you're willing to break some old code, try thinking of function-argument comma as an aggregation operator...then consider what foo = {4, 5, 2} might mean for foo of type, say, (int [3]). First class vector arithmetic, anyone? Now think about the possibilities for natural expression of parallelism in expressions like {foofunc(), 66, p + q}. These are *my* impossible dreams for the future of C. Hey, Bjarne -- any chance you might want to include 1 and 2 above in some future C++ ;-)? -- Eric S. Raymond (the mad mastermind of TMN-Netnews) Email: eric@snark.uu.net CompuServe: [72037,2306] Post: 22 S. Warren Avenue, Malvern, PA 19355 Phone: (215)-296-5718
karl@haddock.ima.isc.com (Karl Heuer) (01/06/89)
(I've added comp.lang.c to the distribution, since a lot of D-designers hang out there, but I've redirected followups back to comp.lang.misc, since that's where the discussion seems to belong. c.l.c readers should subscribe to c.l.m if they want to continue this thread.) In article <9310@ihlpb.ATT.COM> nevin1@ihlpb.UUCP (55528-Liber,N.J.) writes: >In article <2583@ficc.uu.net> peter@ficc.uu.net (Peter da Silva) writes: >>I once modified a version of the small-C compiler to make 'C' a completely >>expression-based language. The changes are really very minor (at least for >>that case... I don't know quite how full 'C' would take it). > >This won't work too well in (full) C. The problem is that pure >expression-based languages (like LISP) tend to be typeless as well. >Having to return a specific data type severely limits the usefulness of making >control-flow constructs (if, switch, for, etc.) expression-oriented. Let's try to define EC, an extension of C with the property that every statement is an expression, yet retaining the property that every expression has a type. All constructs with no reasonable value definition become void expressions. This includes else-less if, default-less switch, any if- or switch-statement with branches of incompatible type, and any top-testing loop. Do-while can be defined to return the value of the last iteration of the loop body. The restriction against test-at-top is annoying, but the language must be prepared to have a value for a loop that executes zero times. This suggests that one ought to be able to attach an `else' clause to such a loop. (I once had a student who kept trying to do this in Pascal...) Of course, since `while (A) B;' is equivalent to `if (A) do B; while (A);', this functionality is already available by explicitly writing `if (A) {do B; while (A);} else C;', but a simple `while (A) B; else (C);' would be a more compact way to write it. (Though it would break C compatibility.) What about break statements? We'd probably be better off with a syntax change, writing `break (EXPR);' to specify the value to be returned by the enclosing loop or switch. If we use the current syntax, then in order for a statement `switch (A) { case 0: B; break; default: C; break; }' to have the obvious value (A==0?B:C), the rule must be that the value of a switch statement is that of the statement *preceding* the break. An analogous rule could be applied to a break inside a do-while. (As always, when the rules do not apply or do not yield a compatible type, the entire expression would be void-valued for all paths.) I'm not sure what to do about continue. If the `else' extension is added, then a continue which causes the loop to exit (because the retested condition is now false) could trigger the `else' clause. (Which would mean that even a do-while would have use for an else.) Alternately, a continue could obtain a value in the same way that a break does, but use it only if the loop test fails. Passing values through a goto doesn't seem to work well, since a label by itself is not a valid statement. Well, I guess we could say that a labeled null statement has the value of the statement preceding the goto, but that's stretching the idea a bit too far, I think. (I did once suggest this for a dialect of TECO: I wanted `5 Ofoo$ ... !foo! UX' to assign 5 to register X, which TECO-10 didn't do.) (Given that so many statements end up being void-valued expressions, is there any point to this language extension? Yes. There are contexts where a statement is not legal, but an expression is, even though its value is not used.) Of course, a simpler approach would be to add valof...resultis from BCPL, or inline functions from C++, but it's not really the same as a true expression language. On the other hand, a language with expression/statement equivalence probably shouldn't be based on C in the first place, since several constructs become redundant (braces vs parens, semicolon vs the comma operator, if-then vs the ternary operator). Karl W. Z. Heuer (ima!haddock!karl or karl@haddock.isc.com), The Walking Lint