An annoying thing with C and languages with C-like syntax is the distinction between statements and expressions. Specifically, that you lose some expressiveness in expression contexts since declarations and statements like for/while/switch etc can't be used in there.
Gcc has an extension to allow blocks inside statements: One just puts a block inside parenthesis and writes statements there. E.g:
({ int y = foo (); int z; if (y > 0) z = y; else z = - y; z; })
The result of the expression is the last statement.
It occurred to me that it would be really simple to add this to pike too. We already have gauge and catch which can open up statement blocks inside expressions, so we only need a variety that returns the value of the last statement expression.
The gcc syntax doesn't work since ({ }) means arrays, so among the existing keywords I picked "inline":
werror ("%d\n", inline { int s = 1; for (int i = 2; i < 7; i++) s *= i; s; });
Type checking of the last statement etc works just fine since the statement/expression distinction doesn't exist on the abstract syntax tree level anyway. If the last statement isn't an expression then the inline block will be of void type, so this gives "assigning a void expression":
mixed c = inline { for (int i = 0; i < 10; i++) werror (" %O\n", i); };
This construct is different from lambdas (implicit or not) since the block is not a function of its own, but rather just another nested block. I.e. it's possible to exit it using "break" and "continue", and "return" will return from the surrounding function.
I only made this for fun and haven't committed it yet. Here's the patch if someone wants to play around with it:
--- src/language.yacc 30 May 2008 11:20:41 -0000 1.426 +++ src/language.yacc 31 May 2008 13:59:55 -0000 @@ -3674,6 +3674,10 @@ free_node ($3); } | expr4 TOK_ARROW line_number_info error {$$=$1; free_node ($3);} + | TOK_INLINE '{' statements comma_expr2 expected_semicolon end_block + { $$ = mknode (F_COMMA_EXPR, $3, $4); } + | TOK_INLINE '{' statements end_block + { $$ = $3; } ;
idents2: idents
The syntax is still open for discussion, of course. It would work to use e.g. "block {...}" instead; the new "block" keyword would not conflict with identifiers.
While playing around with that I noticed some strange behavior when handling void expressions. They apparently gets removed entirely in argument lists. E.g:
void x() {}
int main() { werror ("%O\n", x() + 3); }
This compiles just fine and writes "3". I expected a type error for passing a void argument to `+.
Yes, another keyword would be necessary. What would that be then? I can't think of anything good. Note that in that case it would also have to be a "hard" keyword that would conflict with identifiers, which means more compatibility concerns.
Besides, I think it's mostly a matter of some getting-used-to. Afterall, the construct is essentially a comma expression except some change of characters.
pike-devel@lists.lysator.liu.se