Thu, 25 Sep 2008


Permanent link


"Perl 5 to 6" Lesson 06 - Contexts




    my @a = <a b c>;
    my $x = @a;
    say $x[2];          # c
    say (~2).WHAT;      # (Str)
    say +@a;            # 3
    if @a < 10 { say "short array"; }


When you write something like this

    $x = @a

in Perl 5, $x contains less information than @a - it contains only the number of items in @a. To preserve all information, you have to explicitly take a reference: $x = \@a.

In Perl 6 it's the other way round: by default you don't lose anything, the scalar just stores the array. This was made possible by introducing a generic item context (called scalar in Perl 5) and more specialized numeric, integer and string contexts. Void and List context remain unchanged, though void context is now called sink context.

You can force contexts with special syntax.

    syntax       context

    ~stuff       String
    ?stuff       Bool (logical)
    +stuff       Numeric
    -stuff       Numeric (also negates)
    $( stuff )   Generic item context
    @( stuff )   List context
    %( stuff )   Hash context
     stuff.tree  Tree context

Tree Context

In the early days of Perl 6, there were lots of builtins of which two versions existed, one that returned a flat list, one that returned a list of arrays.

Now this is solved by returning a list of Parcel objects, where the Parcel objects might or might not flatten out depending on the context.

Consider the infix Z (short for zip) operator, which interleaves the elements from two lists:

    my @a = <a b c> Z <1 2 3>;
    say @a.join;                # a1b2c3

What happened here is that the right-hand side of the first statement returned ('a', 1), ('b', 2), ('c', 3), and assignment to an array, which provides list context, flattened out the inner parcels. On the other hand if you write

    my @t = (<a b c> Z <1 2 3>).tree;

then @t now contains three elements, each of which are arrays that don't flatten out.

    for @t -> @inner {
        say "first: @inner[0]  second: @inner[1]"

Produces the output

    first: a  second: 1
    first: b  second: 2
    first: c  second: 3


More specific contexts are a way to delay design choices. For example it seems premature to decide what a list should return in scalar context - a reference to the list would preserve all information, but isn't very useful in numeric comparisons. On the other hand a string representation might be most useful for debugging purposes. So every possible choice disappoints somebody.

With more specific context you don't need to make this choice - it returns some sensible default, and all operators that don't like this choice can simply evaluate the object a more specific context.

For some things (like the Match object), the different contexts really enhance their usefulness and beauty.


[/perl-5-to-6] Permanent link