Chapter 4. Syntax

Language serves not only to express thought but to make possible thoughts which could not exist without it.

Bertrand Russell

Perl 6 is a work in progress, so the syntax is rapidly changing. This chapter is likely to be outdated by the time you read it. Even so, it provides 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 6), 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. This chapter is a first 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 blobs of data that get sucked in, pushed around, altered in various ways, and spat out to some new location. The blobs 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:

@array = ( "Zaphod", "Ford", "Trillian" );

$second_element = @array[1]; # Ford

To get the length of an array—that is, the number of elements in an array—use the .length method. The .last method returns the index of the last element in an array—that is, the highest index in an array.

$count_elements = @array.length;
$last_index = @array.last;

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. These are formed with the pair constructor =>. 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.[5]

$age = %hash{"Zaphod"}; # string
$age = %hash{$name};    # string variable
$age = %hash{$person};  # object

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;

breaks down into a list roughly equivalent to:

(pair1, pair2, pair3, etc...)

While the assignment of the flattened key/value list:

@flat = %hash.kv;

is roughly equivalent to:

(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 and whether it can support indexed access:

$arrayref.length
$hashref.kv

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 structures that normally wouldn’t.

Variables and Context

The primary difference between variables with the $ sigil and variables with @ or % sigils is that they each impose a different context. The $ sigil imposes a scalar context, @ imposes list context, and % imposes hashlist context.[6]

Scalar context

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.

A single element in parentheses is not a list. The comma is the list constructor. Parentheses only group.[7]

So when a one-element list 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];

Again, because a list in scalar context is an arrayref, a hash-like list assigned to a scalar variable is simply a reference to an ordered array of pairs:

$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 entirely different data structures, each with identical values:

@copy = @original;

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, but prevents flattening from outside. 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, while 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 where simple values alternate with array references:

@array =  ( "Marvin", [ "Zaphod", "Ford", "Trillian" ], "Zarniwoop" );

Similarly, in flattening list context a list of array variables are flattened into a single array, while a list of scalar variables are treated as a simple list, even if the scalar variables are arrayrefs. So, the first example produces an array containing all the elements of the three arrays, while the second produces an array of three arrayrefs:

@array = ( @array1, @array2, @array3 ); # single flattened list
@array = ( $arrayref1, $arrayref1, $arrayref3 ); # 3 element list

A lone pair of parentheses is a special token meaning “empty list.” It produces an array structure with no elements in both scalar and list context:

$arrayref = (  );
@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, =>, as follows:

%hash = ( "Zaphod" => 362, "Ford" => 1574, "Trillian" => 28 );

Equally, in hashlist context a list of simple values is treated as a list of pairs. Note that this substitution of two values for a pair object is only possible 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 curly braces alone assigned to a scalar variable define an anonymous subroutine:

# a sub reference that does nothing
$subref = { "Zaphod", 362, "Ford", 1574, "Trillian", 28 };

You can’t use commas in place of pair constructors when assigning a hash reference to a scalar variable, because it’s the => that marks the structure as a hash. So, the hash reference constructor isn’t really {...}, but {... => ...}. If there’s ever any ambiguity, you can also 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 runtime. They may modify only values, not variables. They can be added and removed at any time during the execution of the code. Runtime properties are set with the but keyword:

$true_value = 0 but true;

The true property specifies that the value will always evaluate as true, no matter what it 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.

Internally, properties and traits are stored in hash-like structures with the property name as the key. 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);

Properties have proven to be an incredibly useful and extensible syntax. You’ll see them again and again throughout this chapter. They aren’t restricted to variables and values, but appear on subroutines, methods, classes, grammars, rules, and in parameter lists.

Types

The most important thing to understand about the Perl 6 type system is that it’s completely optional. If you choose to use it, you’ll gain some benefits in optimization and interfacing between languages. The type system isn’t fully defined, but the basic groundwork is in place.

Perl 6 makes a distinction between the type of a value and the type of a variable. A value type specifies what kind of values a variable can hold. Putting an Int type on a scalar says that the scalar holds an integer value:

my Int $scalar;

Putting an Int type on an array says that the array holds integer values:

my Int @array;

And putting an Int type on a hash says that the hash holds integer values:

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 define an implicit variable type, so a variable with no type is just:

my $scalar is Scalar;
my @array is Array;
my %hash is Hash;

Hierarchical data structures can have a complex value type. A hash that holds integer arrays:

my Array of Int %hash;

has the value type Array of Int. The type syntax is flexible, so you could also write that as:

my %hash is 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;


[5] 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.

[6] These three are not the only contexts in Perl 6. A complete discussion of Perl 6 contexts appears in Section 4.2 later in this chapter.

[7] One thread on p6l suggested parentheses as list constructors. This formulation has an unexpected effect in structures that use parentheses for grouping: $val = 10 / (2 + 3) is the value “2”, while $val = ( 10 / (2 + 3)) is an array reference with a single element “2”.

Get Perl 6 Essentials 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.