This page was generated at 2008-05-17 02:01:05 GMT.
(syn r14541, pugs-tests r20436, pugs-smoke r19912)
  [ Index of Synopses ]

TITLE

Synopsis 4: Blocks and Statements

AUTHOR

Larry Wall <larry@wall.org>

VERSION

  Maintainer: Larry Wall <larry@wall.org>
  Date: 19 Aug 2004
  Last Modified: 2 Apr 2008
  Number: 4
  Version: 65

This document summarizes Apocalypse 4, which covers the block and statement syntax of Perl.

The Relationship of Blocks and Declarations

From t/var/var.t lines 19–22 (2 √, 0 ×): (skip)

 

From t/data_types/anon_block.t lines 13–18 (no results): (skip)

 

Every block is a closure. (That is, in the abstract, they're all anonymous subroutines that take a snapshot of their lexical scope.) How a block is invoked and how its results are used are matters of context, but closures all work the same on the inside.

Blocks are delimited by curlies, or by the beginning and end of the current compilation unit (either the current file or the current eval string). Unlike in Perl 5, there are (by policy) no implicit blocks around standard control structures. (You could write a macro that violates this, but resist the urge.) Variables that mediate between an outer statement and an inner block (such as loop variables) should generally be declared as formal parameters to that block. There are three ways to declare formal parameters to a closure.

From t/statements/no_implicit_block.t lines 7–64 (12 √, 0 ×): (skip)

 
    $func = sub ($a, $b) { .print if $a eq $b };  # standard sub declaration
    $func = -> $a, $b { .print if $a eq $b };     # a "pointy" block
    $func = { .print if $^a eq $^b }              # placeholder arguments

A bare closure without placeholder arguments that uses $_ (either explicitly or implicitly) is treated as though $_ were a formal parameter:

    $func = { .print if $_ };   # Same as: $func = -> $_ { .print if $_ };
    $func("printme");

In any case, all formal parameters are the equivalent of my variables within the block. See S06 for more on function parameters.

Except for such formal parameter declarations, all lexically scoped declarations are visible from the point of declaration to the end of the enclosing block. Period. Lexicals may not "leak" from a block to any other external scope (at least, not without some explicit aliasing action on the part of the block, such as exportation of a symbol from a module). The "point of declaration" is the moment the compiler sees "my $foo", not the end of the statement as in Perl 5, so

    my $x = $x;

will no longer see the value of the outer $x; you'll need to say either

    my $x = $OUTER::x;

or

    my $x = OUTER::<$x>;

instead.

If you declare a lexical twice in the same scope, it is the same lexical:

    my $x;
    my $x;

By default the second declaration will get a compiler warning. You may suppress this by modifying the first declaration with proto:

    my proto $x;
    ...
    while my $x = @x.shift {...}              # no warning
    while my $x = @x.shift {...}              # no warning

If you've referred to $x prior to the first declaration, and the compiler tentatively bound it to $OUTER::x, then it's an error to declare it, and the compiler is required to complain at that point. If such use can't be detected because it is hidden in an eval, then it is erroneous, since the eval() compiler might bind to either $OUTER::x or the subsequently declared "my $x".

From t/builtins/my.t lines 29–115 (22 √, 1 ×): (skip)

 

As in Perl 5, "our $foo" introduces a lexically scoped alias for a variable in the current package.

The new constant declarator introduces a lexically scoped name for a compile-time constant, either a variable or a 0-ary sub, which may be initialized with a pseudo-assignment:

    constant Num $pi = 3;
    constant Num π  = atan(2,2) * 4;

The initializing expression is evaluated at BEGIN time.

From t/var/constant.t lines 253–266 (0 √, 1 ×): (skip)

 

There is a new state declarator that introduces a lexically scoped variable like my does, but with a lifetime that persists for the life of the closure, so that it keeps its value from the end of one call to the beginning of the next. Separate clones of the closure get separate state variables.

From t/var/state.t lines 7–27 (3 √, 0 ×): (skip)

 

Perl 5's "local" function has been renamed to temp to better reflect what it does. There is also a let function that sets a hypothetical value. It works exactly like temp, except that the value will be restored only if the current block exits unsuccessfully. (See Definition of Success below for more.) temp and let temporize or hypotheticalize the value or the variable depending on whether you do assignment or binding. One other difference from Perl 5 is that the default is not to undefine a variable. So

From t/var/let.t lines 7–62 (3 √, 8 ×): (skip)

 

From t/var/temp.t lines 7–102 (4 √, 6 ×): (skip)

 
    temp $x;

causes $x to start with its current value. Use

    temp undefine $x;

to get the Perl 5 behavior.

Note that temporizations that are undone upon scope exit must be prepared to be redone if a continuation within that scope is taken.

The Relationship of Blocks and Statements

The return value of a block is the value of its final statement. (This is subtly different from Perl 5's behavior, which was to return the value of the last expression evaluated, even if that expression was just a conditional.)

Statement-ending blocks

A line ending with a closing brace "}", followed by nothing but whitespace or comments, will terminate a statement if an end of statement can occur there. That is, these two statements are equivalent:

    my $x = sub { 3 }
    my $x = sub { 3 };

End-of-statement cannot occur within a bracketed expression, so this still works:

From t/blocks/pointy.t lines 41–49 (4 √, 0 ×): (skip)

 
    my $x = [
        sub { 3 },  # this comma is not optional
        sub { 3 }   # the statement won't terminate here 
    ];

However, a hash composer may never occur at the end of a line. If the parser sees anything that looks like a hash composer at the end of the line, it fails with "closing hash curly may not terminate line" or some such.

    my $hash = {
        1 => { 2 => 3, 4 => 5 },  # OK
        2 => { 6 => 7, 8 => 9 }   # ERROR
    };

Because subroutine declarations are expressions, not statements, this is now invalid:

From t/spec/S02-whitespace_and_comments/unspace.t lines 168–174 (no results): (skip)

 
    sub f { 3 } sub g { 3 }     # two terms occur in a row

But these two are valid:

    sub f { 3 }; sub g { 3 };
    sub f { 3 }; sub g { 3 }    # the trailing semicolon is optional

Though certain control statements could conceivably be parsed in a self-contained way, for visual consistency all statement-terminating blocks that end in the middle of a line must be terminated by semicolon unless they are naturally terminated by some other statement terminator:

    while yin() { yang() }  say "done";      # ILLEGAL
    while yin() { yang() }; say "done";      # okay, explicit semicolon
    @yy := [ while yin() { yang() } ];       # okay within outer [...]
    while yin() { yang() } ==> sort          # okay, ==> separates statements

Conditional statements

From t/statements/if.t lines 9–117 (20 √, 0 ×): (skip)

 

The if and unless statements work much as they do in Perl 5. However, you may omit the parentheses on the conditional:

From t/statements/unless.t lines 13–66 (8 √, 0 ×): (skip)

 
    if $foo == 123 {
        ...
    }
    elsif $foo == 321 {
        ...
    }
    else {
        ...
    }

If the final statement is a conditional which does not execute any branch, the return value is undef in item context and () in list context.

The unless statement does not allow an elsif or else in Perl 6.

From t/statements/unless.t lines 67–74 (2 √, 0 ×): (skip)

 

The value of the conditional expression may be optionally bound to a closure parameter:

From t/statements/if.t lines 118–150 (no results): (skip)

 
    if    testa() -> $a { say $a }
    elsif testb() -> $b { say $b }
    else          -> $b { say $b }

Note that the value being evaluated for truth and subsequently bound is not necessarily a value of type Bool. (All normal types in Perl may be evaluated for truth. In fact, this construct would be relatively useless if you could bind only boolean values as parameters, since within the closure you already know whether it evaluated to true or false.) Binding within an else automatically binds the value tested by the previous if or elsif, which, while known to be false, might nevertheless be an interesting value of false. (By similar reasoning, an unless allows binding of a false parameter.)

An explicit placeholder may also be used:

    if blahblah() { return $^it }

However, use of $_ with a conditional statement's block is not considered sufficiently explicit to turn a 0-ary block into a 1-ary function, so both these methods use the same invocant:

    if .haste { .waste }

(Contrast with a non-conditional statement such as:

    for .haste { .waste }

where each call to the block would bind a new invocant for the .waste method, each of which is likely different from the original invocant to the .haste method.)

Conditional statement modifiers work as in Perl 5. So do the implicit conditionals implied by short-circuit operators. Note though that the first expression within parens or brackets is parsed as a statement, so you can say:

From t/statements/values_in_bool_context.t lines 7–89 (24 √, 0 ×): (skip)

 

From t/statements/modifiers/unless.t lines 9–20 (2 √, 0 ×): (skip)

 

From t/statements/modifiers/if2.t lines 7–25 (2 √, 2 ×): (skip)

 

From t/statements/modifiers/until.t lines 7–28 (3 √, 0 ×): (skip)

 

From t/statements/modifiers/for.t lines 7–69 (8 √, 0 ×): (skip)

 

From t/statements/modifiers/given.t lines 7–19 (2 √, 0 ×): (skip)

 

From t/statements/modifiers/if.t lines 7–20 (2 √, 0 ×): (skip)

 

From t/statements/modifiers/while.t lines 7–29 (3 √, 0 ×): (skip)

 
    @x = 41, (42 if $answer), 43;

and that is equivalent to:

    @x = 41, ($answer ?? 42 !! ()), 43

Loop statements

Looping statement modifiers are the same as in Perl 5 except that, for ease of writing list comprehensions, a looping statement modifier is allowed to contain a single conditional statement modifier:

    @evens = ($_ * 2 if .odd for 0..100);

Loop modifiers next, last, and redo also work as in Perl 5. However, the labelled forms use method call syntax: LABEL.next, etc. The .next and .last methods take an optional argument giving the final value of that loop iteration. So the old next LINE syntax is still allowed but is really short for next LINE: using indirect object syntax. Any block object can be used, not just labels, so to return a value from this iteration of the current block you can say:

From t/statements/next.t lines 6–149 (11 √, 1 ×): (skip)

 

From t/statements/redo.t lines 4–104 (9 √, 1 ×): (skip)

 

From t/statements/last.t lines 6–91 (6 √, 2 ×): (skip)