Perl 6 is a work in progress, so the syntax is rapidly changing. The next four chapters are likely to be outdated by the time you read them. Even so, they provide a good baseline. If you start here, you’ll only have to catch up on a few months of changes (starting with the design documents after Apocalypse 12), instead of several years worth.
Pretend for a moment that you don’t know anything about Perl. You heard the language has some neat features, so you thought you might check it out. You go to the store and pick up a copy of Programming Perl because you think this Larry Wall guy might know something about it. It’s the latest version, put out for the 6.0.1 release of Perl. It’s not a delta document describing the changes, it’s an introduction, and you dive in with the curiosity of a kid who got a telescope for his birthday. These chapters are a glimpse down that telescope.
There’s plenty of time later to analyze each feature and decide which you like and which you don’t. For now, take a step back and get a feel for the system as a whole, for what it’ll be like to work in it.
The most basic building blocks of a
programming
language are its nouns, the chunks of data that get sucked in,
pushed
around, altered in various ways, and spat out to some new location.
The chunks of data are values: strings, numbers, etc., or composites
of the simpler values. Variables are just named containers for those
values. The three kinds of variables in Perl 6 are scalars, arrays,
and hashes. Each has an identifying symbol (or sigil) as part of the
name of the variable: $
for scalars,
@
for arrays, and %
for hashes.
The sigils provide a valuable visual distinction by making it
immediately obvious what kinds of behavior a particular variable is
likely to have. But, fundamentally, there’s little
difference between the three. Each variable is essentially a
container for a value, whether that value is single or collective.
(This statement is an oversimplification, as you’ll
soon see.)
Scalars are all-purpose containers. They can hold strings, integers, floating-point numbers, and references to all kinds of objects and built-in types. For example:
$string = "Zaphod's just this guy, you know?"; $int = 42; $float = 3.14159; $arrayref = [ "Zaphod", "Ford", "Trillian" ]; $hashref = { "Zaphod" => 362, "Ford" => 1574, "Trillian" => 28 }; $subref = sub { print $string }; $object = Android.new;
A filehandle is just an ordinary object in an ordinary scalar variable. For example:
$filehandle = open $filename;
Array variables hold
simple ordered
collections of scalar values. Individual values are retrieved from
the array by numeric
index.
The 0
index holds the first value. The
@
sigil is part of the name of the variable and stays the same no
matter how the variable is used:
@crew = ( "Zaphod", "Ford", "Trillian" ); $second_member = @crew[1]; # Ford
To get the the number of elements in an array use the
.elems
method. The
.last
method returns the index of the last element
in an array—that is, the highest index in an array.
$count_elements = @crew.elems; $last_index = @crew.last;
Pairs hold a
single
key and a single
value. They don’t have a unique sigil because they
rarely appear alone, so they’re stored in scalars,
arrays, or hashes. The pair constructor =>
forms a pair, with the key on the left and value on the right.
$pair = 'key' => 'value';
The alternate option syntax also constructs a pair, with a colon before the key and parentheses around the value:
$pair = :key('value');
The option syntax is useful for subroutine calls, as you’ll see in Section 5.3.1 in Chapter 5.
Hashes are unordered collections of scalar values, stored and retrieved by a key index. The simplest way to build a hash is by passing it a list of anonymous pair objects. For example:
%hash = ( "Zaphod" => 362, "Ford" => 1574, "Trillian" => 28 );
The key for each value may be a string or an object, though there are
some restrictions on object keys. Hashes that use object keys must be
declared as such, for the sake of efficiency. Any object used as a
hash key must have a .id
method that returns a
unique value for each unique object to avoid hashing collisions. This
method is provided by default in the universal base class, so you
only have to worry about uniqueness when you define your own
.id
methods:
$age = %hash{"Zaphod"}; # string $age = %hash{$name}; # string variable $age = %hash{$person}; # object
Quotes are required around literal string keys, so you can call a subroutine to retrieve a key and the subroutine name won’t act as a string key:
$age = %hash{get_key}; # subroutine call
If you really don’t want to type the quotes, substitute auto-quoting brackets for the ordinary curly braces around the key:
$age = %hash«Zaphod»; # string $age = %hash<<Zaphod>>; # ASCII equivalent
In list context, a hash returns a list of key/value pair objects. The
.kv
method returns a flattened list of keys and
values from a hash. So the assignment of a hash directly to an array:
@pairs = %hash;
creates an array of pairs that looks like:
(pair1, pair2, pair3, etc . . . )
However, the assignment of the flattened key/value list:
@flat = %hash.kv;
creates an array of alternating keys and values that looks like:
(key1, value1, key2, value2, etc . . . )
The
.keys
method returns a flattened list of all the keys in a hash. The
.values
method returns a
flattened list of all the values:
@keys = %hash.keys; @values = %hash.values;
References are largely transparent in Perl 6. There is a distinction between references and ordinary variables, but it’s minimized as much as possible in actual use, with automatic referencing and dereferencing where appropriate. Creating a reference to an array or hash requires no special syntax. You simply assign it to a scalar variable:
$arrayref = @array; $hashref = %hash;
References are implicitly dereferenced in many contexts, so array indexes and hash keys access individual elements directly from hashrefs and arrayrefs, just like they do with hashes and arrays:
$arrayref[1] $hashref{"Zaphod"}
Methods are called on arrayrefs and hashrefs just like they are on arrays and hashes. The referent—the underlying data type or object—determines which methods can be used with a particular reference, what those methods do, and whether the reference can support indexed access:
$arrayref.elems $hashref.keys
References to subroutines can be executed simply by passing the reference an argument list. The list can be empty, but the parentheses are required.
$subref($arg);
Arrayrefs and hashrefs have special syntax (@{ . . . }
and %{ . . . }
) for dereferencing them
in contexts that normally wouldn’t:
@array = @{$arrayref}; # or @array = @$arrayref;
Ordinarily, an array reference assigned to an array would produce an
array with a single arrayref element. To copy the individual elements
of $arrayref
to @array
you need
to dereference it first.
One of the main differences
between variables with the $
,
@
, or %
sigils is that they
each impose a different context. The
$
sigil imposes a scalar context, @
imposes list
context, and %
imposes hashlist context.[4]
Scalar context expects a single value. Any array or list evaluated in scalar context returns an arrayref. This means that assigning an array:
@array = ( "Zaphod", "Ford", "Trillian" ); $arrayref = @array;
a list:
$arrayref = ( "Zaphod", "Ford", "Trillian" );
or an explicit anonymous arrayref:
$arrayref = [ "Zaphod", "Ford", "Trillian" ];
to a scalar variable all produce exactly the same structure: a reference to an array with three elements.
The comma is the list constructor, even in scalar context. Parentheses only group. When a single element in parentheses is assigned in scalar context, it stays a simple scalar value:
$value = (20);
If you want to create an arrayref of one element in scalar context,
use square brackets ([ . . . ]
) to explicitly
construct an anonymous array reference:
$arrayref = [20];
A hash-like list assigned to a scalar variable creates a reference to an ordered array of pairs, following the rule that a list in scalar context is an arrayref:
$pair_list = ( "Zaphod" => 362, "Ford" => 1574, "Trillian" => 28 );
You have to use curly braces ({ . . . }
) to
explicitly construct a hash reference in scalar context:
$hashref = { "Zaphod" => 362, "Ford" => 1574, "Trillian" => 28 };
Variables with the @
sigil
impose
flattening-list context. This means
that if you assign one array to another array, the original array is
flattened—treated as if it were a simple list of
values—and every element from
the original array is copied to the new array. The result is that the
two array variables contain different data structures, each with
identical values:
@copy = @original;
Lists also impose flattening-list context. Assigning an array to a list flattens the array and assigns each array element to the corresponding element in the list. If the array has more elements than the list, the remaining elements are simply discarded:
($first, $second, $third) = @array;
A single value in list context is a one-element list, so it produces a one-element array on assignment:
@array = (20); @array = 20; # same
The anonymous arrayref constructor
[ . . . ]
imposes flattening-list context
internally. It doesn’t flatten when used in list
context, though, because flattening-list context
doesn’t flatten references. In scalar context, a
simple list and an arrayref construct produce the same result. But in
list context, a simple list is treated as a flattened list, while an
arrayref construct is treated as a list of one element, an arrayref:
@array = ( "Zaphod", "Ford", "Trillian" ); @array = [ "Zaphod", "Ford", "Trillian" ];
The first example above produces an array with three elements. The second produces an array with one element and that element is a reference to an array with three elements. This is useful for building up complex data structures.
@array = ( "Marvin", [ "Zaphod", "Ford", "Trillian" ], "Zarniwoop" );
Similarly, in flattening-list context a list of array variables are flattened into a single list, while a list of scalar variables are treated as a simple list, even if the scalar variables are arrayrefs:
@array = ( @array1, @array2, @array3 ); # single flattened list @array = ( $arrayref1, $arrayref1, $arrayref3 ); # 3-element list
So, the first example above produces an array containing all the elements of the three arrays, while the second produces an array of three arrayrefs.
A lone pair of parentheses is a special token representing an empty list. It produces an array structure with no elements in both scalar and list context:
$arrayref = ( ); # 0-element arrayref @array = ( ); # 0-element array
Variables with %
sigils impose hashlist context, which expects a list
of
pair objects. This is typically simply
a list of anonymous pairs built with the pair constructor
(=>
):
%hash = ( "Zaphod" => 362, "Ford" => 1574, "Trillian" => 28 );
A list of simple values in hashlist context is treated as a list of pairs. You can substitute two values for a pair object only in hashlist context:
%hash = ( "Zaphod", 362, "Ford", 1574, "Trillian", 28 );
Curly braces { . . . }
are the
anonymous hash reference
constructor, but they don’t impose hashlist context.
This is because an ordinary structure wrapped in curly braces and
assigned to a scalar variable defines an anonymous subroutine:
# a sub reference that returns a list $subref = { "Zaphod", 362, "Ford", 1574, "Trillian", 28 };
The hash reference constructor isn’t really
{ . . . }
, but { . . . => . . . }
, so you can’t use commas in place of
pair constructors when assigning a hash reference to a scalar
variable. It’s the =>
that
marks the structure as a hash. When there is ambiguity, you can force
the right
context by specifying
hash
or sub
before the block:
$subref = sub { print "Lost luggage.\n"; } $hashref = hash { "Zaphod", 362, "Ford", 1574, "Trillian", 28 };
Properties allow additional information to be attached to variables and values. As Damian likes to explain it, they’re much like sticky notes. You can take a note, scribble some important information on it, and slap it onto the refrigerator, your monitor, or the dashboard of your car. When you’re done, you peel it off and throw it away.
Some properties are attached at compile time. These are known as
traits. Traits are still properties, just a
particular kind of property. Traits are fixed to the variable when it
is declared and cannot be changed later.
Compile-time traits are set with the
is
keyword:
my $pi is constant = 3.14159;
The
constant
trait specifies that the value of the variable can’t
be changed.
Other properties are attached at run-time. They only modify values,
not variables. They can be added and removed at any time during the
execution of the code. Run-time properties are set with the
but
keyword:
$true_value = 0 but true;
The true
property specifies that the value will
evaluate as true in a Boolean context, no matter what the actual
value is. This particular property means the Perl 6
system
call can be checked with a simple
conditional. It still returns the same numeric values it always has
(0 on success and a numeric error code on failure), but it flags the
value with a property as true when the call succeeds and false when
it fails.
Properties and traits can also store a value. Both
constant
and true
define their
own values when they’re set. Some properties take
arguments for their value:
my @array is dim(2,5,42); # specify dimensions
Properties have proven to be an incredibly useful and extensible syntax. You’ll see them again and again throughout the next few chapters. They aren’t restricted to variables and values, but appear on subroutines, methods, classes, grammars, rules, and in parameter lists.
Perl 6 allows you to specify the types of variables and values much more precisely than Perl 5, but keep in mind that explicit types are completely optional. If you choose to use them, you’ll gain some benefits in optimization and interfacing between languages. The design of the type system isn’t complete, but the basic groundwork is in place.
Perl 6 makes a distinction between the type of a value and the type
of a variable. The value type specifies what
kind of values a variable can hold. Putting an Int
value type on a scalar says that the scalar can only hold an integer
value:
my Int $scalar;
Putting an Int
value type on an array says that the
array holds integer values:
my Int @array;
And putting an Int
value type on a hash says that
the hash holds integer values (but says nothing about the type of the
keys):
my Int %hash;
The variable type specifies what kind of
container the variable is. This is basically like a tie in Perl 5.
Variable types are defined as traits of the variable, with the
is
keyword. The sigils provide an
implicit variable type, so a variable with
no type is just:
my $scalar is Scalar; my @array is Array; my %hash is Hash;
But you can also define your own classes to implement a variable type:
my $scalar is FileHandle; my @array is Matrix; my %hash is BerkeleyDB;
Hierarchical data structures can have a
complex value type. A hash that holds integer arrays has the value
type Array of Int
:
my Array of Int %hash;
The type syntax is flexible, so you could also write that as:
my %hash is Hash of Array of Int; # or my %hash of Array of Int;
and get the same data structure. This improves readability, especially in multilevel data structures:
my Array of Hash of Array of Int %hash; my %hash is Hash of Array of Hash of Array of Int;
[4] These three are not the only contexts in Perl 6. A complete discussion of Perl 6 contexts appears in Section 4.2.7 later in this chapter.
Get Perl 6 and Parrot Essentials, Second Edition now with the O’Reilly learning platform.
O’Reilly members experience books, live events, courses curated by job role, and more from O’Reilly and nearly 200 top publishers.