Sign In/My Account | View Cart  
advertisement


Listen Print

Exegesis 3
by Damian Conway | Pages: 1, 2, 3, 4, 5, 6, 7

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

Seek and ye shall flatten

Having grabbed the entire file, we now rewind and truncate it, in preparation for writing it back:
    seek $data.{fh}: *@StartOfFile;
    truncate $data.{fh}: 0;
You're probably wondering what's with the asterisk ... unless you've ever tried to write:
    seek $filehandle, @where_and_whence;
in Perl 5 and gotten back the annoying "Not enough arguments for seek" exception. The problem is that seek expects three distinct scalars as arguments (as if it had a Perl 5 prototype of seek($$$)), and it's too fastidious to flatten the proffered array in order to get them.

It's handy to wrap the magical 0,0 arguments of the seek in a single array (so we no longer have to remember this particular incantation), but to use such an array in Perl 5 we would then have to write:

    seek $data->{fh}, $StartOfFile[0], $StartOfFile[1];    # Perl 5
In Perl 6 that's not a problem, because we have * -- the list context specifier. When used in an argument list, it takes whatever you give it (typically an array or hash) and flattens it. So:
    seek $data.{fh}: *@StartOfFile;                        # Perl 6
massages the single array into a list of two scalars, as seek requires.

Oh, and yes, that is the adverbial colon again. In Perl 6, seek and truncate are both methods of filehandle objects. So we can either call them as:

    $data.{fh}.seek(*@StartOfFile);
    $data.{fh}.truncate(0);
Or use the "indirect object" syntax:
    seek $data.{fh}: *@StartOfFile;
    truncate $data.{fh}: 0;
And that's where the colon comes in. Another of its many uses in Perl 6 is to separate "indirect object" arguments (e.g. filehandles) from the rest of the argument list. The main place you'll see colons guarding indirect objects is in print statements (as described in the next section).

It is written...

Finally, &save_data has everything ready and can write the four fields and the rest of the file back to disk. First, it sets the output field separator for the filehandle (i.e. the equivalent of Perl 5's $, variable) to inject newlines between elements:

    $data.{fh}.ofs("\n");
Then it prints the fields to the filehandle:
    print $data.{fh}: $data.{qw(name vers stat)}, _@{$data.{costs}}, $rest;

Note the use of the adverbial colon after $data.{fh} to separate the filehandle argument from the items to be printed. The colon is required because it's how Perl 6 eliminates the nasty ambiguity inherent in the "indirect object" syntax. In Perl 5, something like:

    print foo bar;

could conceivably mean:

    print {foo} (bar);    # Perl 5: print result of bar() to filehandle foo

or

    print ( foo(bar) );   # Perl 5: print foo() of bar() to default filehandle

or even:

    print ( bar->foo );   # Perl 5: call method foo() on object returned by
                          #         bar() and print result to default filehandle

In Perl 6, there is no confusion, because each indirect object must followed by a colon. So in Perl 6:

    print foo bar;

can only mean:

    print ( foo(bar) );   # Perl 6: print foo() of bar() to default filehandle

and to get the other two meanings we'd have to write:

    print foo: bar;       # Perl 6: print result of bar() to filehandle foo()
                          #         (foo() not foo, since there are no
                          #          bareword filehandles in Perl 6)

and:

    print foo bar: ;      # Perl 6: call method foo() on object returned by
                          #         bar() and print result to default filehandle

In fact, the colon has an even wider range of use, as a general-purpose "adverb marker"; a notion we will explore more fully below.

String 'em up together

CGI Programming With PerlCGI Programming with Perl, 2nd Ed
By Scott Guelich, Shishir Gundavaram & Gunther Birznieks
2nd Edition July 2000
1-56592-419-3, Order Number: 4193
466 pages, $34.95

The printed arguments are: a hash slice:

    $data.{qw(name vers stat)},
a stringified dereferenced nested array:
     _@{$data.{costs}},
and a scalar:
    $rest;
The new hash slice syntax was explained in the previous Apocalypse/Exegesis, and the scalar is just a scalar, but what was the middle thing again?

Well, $data.{costs} is just a regular Perl 6 access to the 'costs' entry of the hash referred to by $data. That entry contains the array reference that was the result of splitting $cost in &load_data.

So to get the actual array itself, we can prefix the array reference with a @ sigil (though, technically, we don't have to: in Perl 6 arrays and array references are interchangeable in scalar context).

That gives us @{$data.{costs}}. The only remaining difficulty is that when we print the list of items produced by @{$data.{costs}}, they are subject to the output field separator. Which we just set to newline.

But what we want is for them to appear on the same line, with a space between each.

Well ... evaluating a list in a string context does precisely that, so we could just write:

    "@{$data.{costs}}"    # evaluate array in string context
But Perl 6 has another alternative to offer us -- the unary underscore operator. Binary underscore is string concatenation, so it shouldn't be too surprising that unary underscore is the stringification operator (think: concatenation with a null string). Prefixing any expression with an underscore forces it to be evaluated in string context:
    _@{$data{costs}}     # evaluate array in string context
Which, in this case, conveniently inserts the required spaces between the elements of the costs array.

Pages: 1, 2, 3, 4, 5, 6, 7

Next Pagearrow