block expressions vs. reveal

Dave Herman dherman at
Thu Jan 8 08:57:17 PST 2009

[NB: I agree with Mark that we should not focus too much on concrete 
syntax yet, so I'll also plead for people to avoid quibbling with 
details of syntax for the moment.]

Instead of "reveal" I'd prefer block expressions with a fixed (but 
optional) tail expression:

     BlockExpr ::= "{" (Stmt|Decl)* ("=>" Expr)? "}"

The semantics would be like a block statement, but the result value is 
the result of the tail expression, or the undefined value if it's 
omitted. The tail expression would be in the same scope chain as the 
whole block but would be a mandatory tail call.

This would be used for the body of lambdas, and addresses Waldemar's 
concern about unintended leakage. It admits an extremely simple 
definition of tail position.

Moreover, it could be part of a let expression form:

     Expr ::= ... | "let" LetHead BlockExpr

This single form functions as an expression or a statement, without the 
need for two separate forms. (MarkM would probably like for the LetHead 
to be optional, which is unproblematic but a detail we can postpone 

     function foo(x) {
         // let expression used as an expression
         frob(let (y = x + 1) {
                  print("hello, world!");
                  => baz(y)

     function bar(x) {
         // let expression used as a statement
         let (y = x + 1) {
             f(x); g(y); h(x,y);

To contrast with "reveal": when there's mutable state I'd prefer it to 
be explicit. Anything you might do with reveal you could do with let 
expressions using a local variable. For example:

     lambda(x){ if (p()) reveal(1); else reveal(2); }

could be expressed as

     lambda(x) { let tmp; if (p()) tmp = 1; else tmp = 2; => tmp }

As I say, I prefer not to hide the mutation.


More information about the Es-discuss mailing list