O'Reilly logo

Perl 6 and Parrot Essentials, Second Edition by Leopold Tötsch, Dan Sugalski, Allison Randal

Stay ahead with the world's most comprehensive technology and business learning platform.

With Safari, you learn the way you learn best. Get unlimited access to videos, live online training, learning paths, books, tutorials, and more.

Start Free Trial

No credit card required

Chapter 4. Basic Syntax

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.

Variables

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

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;

Arrays

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

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

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

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.

Variables and Context

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

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 };

List context

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

Hashlist context

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 and Traits

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.

Types

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.

With Safari, you learn the way you learn best. Get unlimited access to videos, live online training, learning paths, books, interactive tutorials, and more.

Start Free Trial

No credit card required