Skip to end of metadata
Go to start of metadata

A left brace, possibly preceded by one or more labels, introduces a block. The execution of this block may immediate or not, depending on the surrounding syntax.

Here is an example of two blocks that are immediately executed:

Here is an example of a block whose execution is delayed and conditional on data structure:

Here is an example where the distinction is blurred, and depends on the implementation of the syntax 'using':

One of the charms of this treatment of blocks (inherited from Ruby) is that it enables constructed like 'using' to be defined in terms of regular methods.

In most situations, a block is executed immediately. Such a block may be called an open block because the compiler is guaranteed to open-code it, and because it is the opposite of the other kind of block we are about to call "closed".

But in some situations, the block as a whole is closed. That is, it is turned into a method-like value called a closure. This value may then be passed as an argument to other methods, which may eventually execute the code inside the block one or more times.

A block is closed under any of the following circumstances:

  • It contains an explicit argument list (even an empty one).
  • ?? It appears as a subexpression. (Conflict with statements have values!)
  • It is appended to a method call.

An argument list is simply zero or more names separated by commas, or else a method's argument list (enclosed in parentheses). An argument list is always terminated by a bar '|' character.

A block is appended to a method call under the following circumstances:

  • It immediately follows the closing parenthesis of a method invocation.
    Examples: range(1,10).each {code}; myMethod() {code}
  • It immediately follows a method reference.
    Examples: myCtln.each {code}; myMethod {code}
  • ? It follows the open parenthesis, comma, or colon of a method invocation.
    Examples: myCtln.each({code}); doTimes(1,10,{code})

The third rule supports the principle that empty method argument lists may always be elided.

When a series of blocks immediately follows a method invocation (possibly with arguments, and possibly after a label), we say (as a matter of syntax) that every such block is appended to the method invocation. As a value, it is also appended to the method's argument list.

(Issue: The third rule does not buy very much, given the first rule. Do we really need it, or shall we use that syntax for something else, such as value-producing blocks?)

Note: When one token is said to "immediately follow" another, only whitespace and comments may intervene between them, and no unescaped line breaks may appear between the tokens.

A block may be forced closed by giving it an empty argument list, and a block without an argument list may be forced open by preceding it by a newline or wrapping it in parentheses.

The purpose of these rules is to allow one kind of syntax (curly braces) to express two constructs which are distinct but related, and highly frequent: ordinary open blocks and closures.

Whether the block is closed or open, the code inside the block is governed by the ordinary rules of syntax and semantics. In particular, variable references in both open and closed blocks are subject to the same scoping rules. See block syntax.

(Issue: Do we want 'it' to be an implicitly bound name in all closed, argument-free blocks? jrose thinks this is buying trouble.)

Blocks can be prefixed with one or more labels. Any such label is syntactically part of the block. Just as an unlabeled block is appended to a method call if and only if its opening brace immediately follows a suitable part of the method, such as the closing parenthesis of its argument list, so a labeled block is appended if and only if its first label is in a similar suitable location.

  • No labels