Sign In/My Account | View Cart  
advertisement


Listen Print

Synopsis 6

by Damian Conway, Allison Randal
April 09, 2003

Editor's note: this document is out of date and remains here for historic interest. See Synopsis 6 for the current design information.

This document summarizes Apocalypse 6, which covers subroutines and the new type system.

Subroutines and Other Code Objects

Subroutines (keyword: sub) are noninheritable routines with parameter lists.

Methods (keyword: method) are inheritable routines that always have an associated object (known as their invocant) and belong to a particular class.

Submethods (keyword: submethod) are noninheritable methods, or subroutines masquerading as methods. They have an invocant and belong to a particular class.

Multimethods (keyword: multi) are routines that do not belong to a particular class, but which have one or more invocants.

Rules (keyword: rule) are methods (of a grammar) that perform pattern matching. Their associated block has a special syntax (see Synopsis 5).

Macros (keyword: macro) are routines whose calls execute as soon as they are parsed (i.e. at compile-time). Macros may return another source code string or a parse-tree.

Standard Subroutines

The general syntax for named subroutines is any of:


     my RETTYPE sub NAME ( PARAMS ) TRAITS {...}
    our RETTYPE sub NAME ( PARAMS ) TRAITS {...}
                sub NAME ( PARAMS ) TRAITS {...}

The general syntax for anonymous subroutines is:


    sub ( PARAMS ) TRAITS {...}

"Trait" is the new name for a compile-time (is) property. See Traits and Properties

Perl5ish Subroutine Declarations

You can still declare a sub without parameter list, as in Perl 5:


    sub foo {...}

Arguments still come in via the @_ array, but they are constant aliases to actual arguments:


    sub say { print qq{"@_"\n}; }   # args appear in @_

    sub cap { $_ = uc $_ for @_ }   # Error: elements of @_ are constant

If you need to modify the elements of @_, then declare it with the is rw trait:


    sub swap (*@_ is rw) { @_[0,1] = @_[1,0] }

Blocks

Raw blocks are also executable code structures in Perl 6.

Every block defines a subroutine, which may either be executed immediately or passed in as a Code reference argument to some other subroutine.

"Pointy subs"

The arrow operator -> is almost a synonym for the anonymous sub keyword. The parameter list of a pointy sub does not require parentheses and a pointy sub may not be given traits.


    $sq = -> $val { $val**2 };  # Same as: $sq = sub ($val) { $val**2 };

    for @list -> $elem {        # Same as: for @list, sub ($elem) {
        print "$elem\n";        #              print "$elem\n";
    }                           #          }

Stub Declarations

To predeclare a subroutine without actually defining it, use a "stub block":


    sub foo {...};     # Yes, those three dots are part of the actual syntax

The old Perl 5 form:


    sub foo;

is a compile-time error in Perl 6 (for reasons explained in Apocalypse 6).

Globally Scoped Subroutines

Subroutines and variables can be declared in the global namespace, and are thereafter visible everywhere in a program.

Global subroutines and variables are normally referred to by prefixing their identifier with *, but it may be omitted if the reference is unambiguous:


    $*next_id = 0;
    sub *saith($text)  { print "Yea verily, $text" }

    module A {
        my $next_id = 2;    # hides any global or package $next_id
        saith($next_id);    # print the lexical $next_id;
        saith($*next_id);   # print the global $next_id;
    }

    module B {
        saith($next_id);    # Unambiguously the global $next_id
    }

Lvalue Subroutines

Lvalue subroutines return a "proxy" object that can be assigned to. It's known as a proxy because the object usually represents the purpose or outcome of the subroutine call.

Subroutines are specified as being lvalue using the is rw trait.

An lvalue subroutine may return a variable:


    my $lastval;
    sub lastval () is rw { return $lastval }
 
or the result of some nested call to an lvalue subroutine:

    sub prevval () is rw { return lastval() }

or a specially tied proxy object, with suitably programmed FETCH and STORE methods:


    sub checklastval ($passwd) is rw {
        my $proxy is Proxy(
                FETCH => sub ($self) {
                            return lastval();
                         },
                STORE => sub ($self, $val) {
                            die unless check($passwd);
                            lastval() = $val;
                         },
        );
        return $proxy;
    }

Operator Overloading

Operators are just subroutines with special names.

Unary operators are defined as prefix or postfix:


    sub prefix:OPNAME  ($operand) {...}
    sub postfix:OPNAME ($operand) {...}

Binary operators are defined as infix:


    sub infix:OPNAME ($leftop, $rightop) {...}

Bracketing operators are defined as circumfix. The leading and trailing delimiters together are the name of the operator.


    sub circumfix:LEFTDELIM...RIGHTDELIM ($contents) {...}
    sub circumfix:DELIMITERS ($contents) {...}

If the left and right delimiters aren't separated by "...", then the DELIMITERS string must have an even number of characters. The first half is treated as the opening delimiter and the second half as the closing.

Operator names can be any sequence of Unicode characters. For example:


    sub infix:(c)        ($text, $owner) { return $text but Copyright($owner) }
    method prefix:± (Num $x) returns Num { return +$x | -$x }
    multi postfix:!             (Int $n) { $n<2 ?? 1 :: $n*($n-1)! }
    macro circumfix:<!--...-->   ($text) { "" }

    my $document = $text (c) $me;

    my $tolerance = ±7!;

    <!-- This is now a comment -->

Parameters and Arguments

Perl 6 subroutines may be declared with parameter lists.

By default, all parameters are constant aliases to their corresponding arguments -- the parameter is just another name for the original argument, but the argument can't be modified through it. To allow modification, use the is rw trait. To pass-by-copy, use the is copy trait.

Parameters may be required or optional. They may be passed by position, or by name. Individual parameters may confer a scalar or list context on their corresponding arguments.

Arguments destined for required parameters must come before those bound to optional parameters. Arguments destined for positional parameters must come before those bound to named parameters.

Invocant Parameters

A method invocant is specified as the first parameter in the parameter list, with a colon (rather than a comma) immediately after it:


    method get_name ($self:) {...}
    method set_name ($me: $newname) {...}

The corresponding argument (the invocant) is evaluated in scalar context and is passed as the left operand of the method call operator:


    print $obj.get_name();
    $obj.set_name("Sam");

Multimethod invocants are specified at the start of the parameter list, with a colon terminating the list of invocants:


    multi handle_event ($window, $event: $mode) {...}    # two invocants

Multimethod invocant arguments are passed positionally, though the first invocant can be passed via the method call syntax:


    # Multimethod calls...
    handle_event($w, $e, $m);
    $w.handle_event($e, $m);

Invocants may also be passed using the indirect object syntax, with a colon after them. The colon is just a special form of the comma, and has the same precedence:


    # Indirect method call...
    set_name $obj: "Sam";

    # Indirect multimethod call...
    handle_event $w, $e: $m;

Passing too many or too few invocants is a fatal error.

The first invocant is always the topic of the corresponding method or multimethod.

Pages: 1, 2, 3, 4

Next Pagearrow