block expressions vs. reveal
On Thu, Jan 8, 2009 at 8:57 AM, Dave Herman <dherman at ccs.neu.edu> wrote:
[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)? "}"
In the spririt of postponing concrete syntax issues, I suggest we continue to use placeholder identifiers. In particular, some have advocated "^" for "lambda" and here suggest "=>" for "reveal". To a Scala programmer, "=>" (but infix) is more natural for "lambda". To a Smalltalk programmer, "^" is more natural for "reveal". Since we've got swapped possibilities for the same pair, let's avoid them for now.
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 discussing.)
Correct. I like all this.
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); }
I'm happy to drop my original proposal in favor of yours. I think I like yours better anyway. But for the record, mine was declarative and the above would have been illegal under the "no more than once not nested" restrictions.
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.
For this case, that's how you'd have to write it in my proposal as well.
[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:
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:
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 discussing.)
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:
could be expressed as
As I say, I prefer not to hide the mutation.