Sign In/My Account | View Cart  
advertisement


Listen Print

Apocalypse 6
by Larry Wall | Pages: 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16

Editor's Note: this Apocalypse is out of date and remains here for historic reasons. See Synopsis 06 for the latest information.

Defaults

Default values are also traits, but are written as assignments and must come at the end of the formal parameter for psychological reasons.


    rule defval :w { \= <item> }

That is:


    sub trim ( Str $_ is rw, Rule ?$remove = /\s+/ ) {
            s:each/^ <$remove> | <$remove> $//;
    }

lets you call trim as either:


    trim($input);

or:


    trim($input, /\n+/);

It's very important to understand that the expression denoted by item is evaluated in the lexical scope of the subroutine definition, not of the caller. If you want to get at the lexical scope of the caller, you have to do it explicitly (see CALLER:: below). Note also that an item may not contain unbracketed commas, or the parser wouldn't be able to reliably locate the next parameter declaration.

Although the default looks like an assignment, it isn't one. Nor is it exactly equivalent to //=, because the default is set only if the parameter doesn't exist, not if it exists but is undefined. That is, it's used only if no argument is bound to the parameter.

An rw parameter may only default to a valid lvalue. If you find yourself wanting it to default to an ordinary value because it's undefined, perhaps you really want //= instead:


    sub multprob ($x is rw, $y) {
        $x //= 1.0;     # assume undef means "is certain"
        $x *= $y;
    }

Syntactically, you can put a default on a required parameter, but it would never be used because the argument always exists. So semantic analysis will complain about it. (And I'd rather not say that adding a default implies it's optional without the ? zone marker.)

Formal parameter types

Formal parameters may have any type that any other variable may have, though particular parameters may have particular restrictions. An invocant needs to be an object of an appropriate class or subclass, for instance. As with ordinary variable declarations the type in front is actually the return type, and you can put it afterwards if you like:


    sub foo (int @array is rw) {...}
    sub foo (@array of int is rw) {...}
    sub foo (@array is Array of int is rw) {...}

The type of the actual argument passed must be compatible with (but not necessarily identical to) the formal type. In particular, for methods the formal type will often indicate a base class of the actual's derived class. People coming from C++ must remember that all methods are "virtual" in Perl.

Closure parameters are typically declared with &:


    sub mygrep (&block, *@list is rw) {...}

Within that subroutine, you can then call block() as an ordinary subroutine with a lexically scoped name. If such a parameter is declared without its own parameter signature, the code makes no assumptions about the actual signature of the closure supplied as the actual argument. (You can always inspect the actual signature at run time, of course.)

You may, however, supply a signature if you like:


    sub mygrep (&block($foo), *@list is rw) {
        block(foo => $bar);
    }

With an explicit signature, it would be error to bind a block to &block that is not compatible. We're leaving "compatible" undefined for the moment, other than to point out that the signature doesn't have to be identical to be compatible. If the actual subroutine accepted one required parameter and one optional, it would work perfectly fine, for instance. The signature in mygrep is merely specifying what it requires of the subroutine, namely one positional argument named "$foo". (Conceivably it could even be named something different in the actual routine, provided the compiler turns that call into a positional one because it thinks it already knows the signature.)

Calling subroutines

The typical subroutine or method is called a lot more often than it is declared. So while the declaration syntax is rather ornate, we strive for a call syntax that is rather simple. Typically it just looks like a comma-separated list. Parentheses are optional on predeclared subroutine calls, but mandatory otherwise. Parentheses are mandatory on method calls with arguments, but may be omitted for argumentless calls to methods such as attribute accessors. Parentheses are optional on multimethod and macro calls because they always parse like list operators. A rule may be called like a method but is normally invoked within a regex via the <rule> syntax.

As in Perl 5, within the list there may be an implicit transition from scalar to list context. For example, the declaration of the standard push built-in in Perl 6 probably looks like this:


    multi *push (@array, *@list) {...}

but you still generally call it as you would in Perl 5:


    push(@foo, 1, 2, 3);

This call has two of the three kinds of call arguments. It has one positional argument, followed by a variadic list. We could imagine adding options to push sometime in the future. We could define it like this:


    multi *push (@array, ?$how, *@list) {...}

That's just an optional positional parameter, so you'd call it like this:


    push(@foo, "rapidly", 1,2,3)

But that won't do, actually, since we used to allow the list to start at the end of the positional parameters, and any pre-existing push(@foo,1,2,3) call to the new declaration would end up mapping the "1" onto the new optional parameter. Oops...

If instead we force new parameters to be in named notation, like this:


    multi *push (@array, *@list, +$how) {...}

tèen we can say:


    push(@foo, how => "rapidly", 1,2,3)and it's no longer ambiguous.  Since dhow is iî the named-only zone,
it can never be set positionally, and the old calls to:


    push(@foo, 1,2,3);

still work fine, because *@list is still at the end of the positional parameter zone. If we instead declare that:


    multi *push (@array, +$how, *@list) {...}

we could still say:


    push(@foo, how => "rapidly", 1,2,3)

but this becomes illegal:


    push(@foo, 1,2,3);

because the slurpy array is in the named-only zone. We'll need an explicit way to indicate the start of the list in this case. I can think of lots of (mostly bad) ways. You probably can too. We'll come back to this...

Actual arguments

So the actual arguments to a Perl function are of three kinds: positional, named, and list. Any or all of these parts may be omitted, but whenever they are there, they must occur in that order. It's more efficient for the compiler (and less confusing to the programmer) if all the positional arguments come before all the non-positional arguments in the list. Likewise, the named arguments are constrained to occur before the list arguments for efficiency--otherwise the implementation would have to scan the entire list for named arguments, and some lists are monstrous huge.

We'd call these three parts "zones" as well, but then people would get them confused with our six declarative zones. In fact, extending the zoning metaphor a bit, our three parts are more like houses, stores, and factories (real ones, not OO ones, sheesh). These are the kinds of things you actually find in residential, commercial, and industrial zones. Similarly, you can think of the three different kinds of argument as the things you're allowed to bind in the different parameter zones.

A house is generally a scalar item that is known for its position; after all, "there's no place like home". Um, yeah. Anyway, we usually number our houses. In the US, we don't usually name our houses, though in the UK they don't seem to mind it.

A store may have a position (a street number), but usually we refer to stores by name. "I'm going out to Fry's" does not refer to a particular location, at least not here in Silicon Valley. "I'm going out to McDonald's" doesn't mean a particular location anywhere in the world, with the possible exception of "not Antarctica".

You don't really care exactly where a factory is--as long as it's not in your back yard--you care what it produces. The typical factory is for mass producing a series of similar things. In programming terms, that's like a generator, or a pipe...or a list. And you mostly worry about how you get vast quantities of stuff into and out of the factory without keeping the neighbors awake at night.

So our three kinds of arguments map onto the various parameter zones in a similar fashion.

The positional arguments

Obviously, actual positional arguments are mapped onto the formal parameters in the order in which the formal positional parameters are declared. Invocant parameters (if any) must match invocant arguments, the required parameters match positional arguments, and then any additional non-named arguments are mapped onto the optional positional parameters. However, as soon as the first named argument is seen (that cannot be mapped to an explicitly typed Pair or Hash parameter) this mapping stops, and any subsequent positional parameters may only be bound by name.

The named arguments

After the positional argument part, you may pass as many named pairs as you like. These may bind to any formal parameter named in the declaration, whether declared as positional or named. However, it is erroneous to simultaneously bind a parameter both by position and by name. Perl may (but is not required to) give you a warning or error about this. If the problem is ignored, the positional parameter takes precedence, since the name collision might have come in by accident as a result of passing extra arguments intended for a different routine. Problems like this can arise when passing optional arguments to all the base classes of the current class, for instance. It's not yet clear how fail-soft we should be here.

Named arguments can come in either as Pair or Hash references. When parameter mapper sees an argument that is neither a Pair nor a Hash, it assumes it's the end of the named part and the beginning of the list part.

All unbound named arguments are bound to elements of the slurpy hash, if one was declared. If no slurpy hash is declared, an exception is thrown (although some standard methods, like BUILD, will provide an implicitly declared slurpy hash--known as %_ by analogy to @_--to handle surplus named arguments).

At the end of named argument processing, any unmapped optional parameter ends up with the value undef unless a default value is declared for it. Any unmapped required parameter throws an exception.

The slurpy array

All remaining arguments are bound to the slurpy array, if any. If no slurpy array is specified, any remaining arguments cause an exception to be thrown. (You only get an implicit *@_ slurpy array when the signature is omitted entirely. Otherwise we could never validly give the error "Too many arguments".)

No argument processing is done on this list. If you go back to using named pairs at the end of the list, for instance, you'll have to pop those off yourself. But since the list is potentially very long, Perl isn't going to look for those on your behalf.

Indeed, the list could be infinitely long, and maybe even a little longer than that. Perl 5 always flattens lists before calling the subroutine. In Perl 6, list flattening is done lazily, so a list could contain several infinite entries:


    print(1..Inf, 1..Inf);

That might eventually give the print function heartburn, of course...

Pages: 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16

Next Pagearrow