Code blocks (was Re: Proposal: opt-out local scoping)

Yuh-Ruey Chen maian330 at gmail.com
Sat Aug 30 09:52:04 PDT 2008


Mark S. Miller wrote:
> Since ES is not an expression language, it's useful to divide the question into
>
> * TC for expressions
>    expr equiv (function(){return expr;})()
>    ES violations: this, arguments.
>    'this' breakage can possibly be addressed with '.bind(this)' as in
> my previous message.
>    expr equiv (function(){return expr;}).call(this)
>
> * TC for blocks
>    {stats} equiv (function(){stats})();
>    Same issues re this, arguments
>    Additional ES violations: return, break, continue, var hoisting
>
> Note: The above litany of problems are not fixable in ES. But we
> should try to avoid digging this hole any deeper.

Any procedural language will have issues with TC then. The only longterm
solution to this that I can think of is to add Ruby-like code blocks to
the language, which inherit this, arguments, var scope, and
return/break/continue continuations.

Not ever having dealt with implementing continuations, I have no idea
how simple it would be to add code block semantics to the language.

There are two styles to code blocks that I know of, which are not
mutually exclusive:
1) adding a new type of function
2) denoting that a parameter to a function is a block, and treating any
function passed in as that parameter to be a block

In either style, the function artifacts (this, arguments, etc.) would be
determined lexically.

The first style would require some new syntax to define blocks.
Redefining |this| via function.call and function.apply should also be
disallowed. We have several options to choose from. Some examples:

Ruby-like:
    do(...) { ... }
    do { ... }

Usage of Java keywords:
    function(...) inherits { ... }

Some obscure yet convenient syntax:
    #(...) { ... }

The second style would require some sort of block annotation to a
parameter, e.g.

    function(x: block} { ... }
    function(block x) { ... }
    function(&x) { ... }

One advantage of the second style is that we can add new types of
control abstractions relatively seamlessly with some more Ruby-like
sugar. If the last parameter to a function is annotated to be a block,
then the following:

    function control(..., block f) { ... }

    control(...) statement

would pass in a 0-parameter code block composed of |statement| (which
could be a {...} block) to the function |control| as the parameter f.
Example:

    function read(openArg, block f) {
        try {
           this.open(openArg);
           f();
        } finally {
           this.close();
        }
    }
   
    FileInputStream.prototype.read = read;
   
    function findInFiles(files, x) {
        for each (let file in files) {
            input = new FileInputStream();
            input.read(file) {
                let lineNum = 0;
                for (let line in input.readLines()) {
                    if (line == x)
                        return [file, lineNum];
                    lineNum++;
                }
            }
        }
    }

Hope that all made sense.

-Yuh-Ruey Chen


More information about the Es-discuss mailing list