Chapter 1. Introduction
This chapter is the big picture view of the language; don’t worry if you don’t understand everything that’s going on just yet. Worry if you get to the end of the book and you still don’t! There’s much going on, so you’ll spiral around some topics, revisit others, and with some practice see how it all fits together—it really is all about the practice.
Why Perl 6?
For starters, you have Learning Perl 6. You might as well get your money’s worth by using the language!
But what makes this an attractive language? The Perl family has always been fond of DWIM—Do What I Mean. Things that you do frequently should be easy to do, and the hardest things should still be possible. The usefulness of any programming language is measured by the extent to which it solves your problems.
Perl 6 is a great text processing language—possibly even better than Perl 5. The regular expressions (Chapter 15) have many new and exciting features that make it even easier to match and extract bits of text. The builtin grammar (Chapter 17) features allow you to easily write complex rules to handle and react to text.
Gradual typing (Chapter 3) allows you to annotate variables with restrictions about what you can store there. For example, you can specify that a number must be a whole number, or a positive number, or between two other numbers. You don’t have to use it (that’s the gradual part). You’ll be able to annotate what a subroutine accepts and what it should return. That can quickly reveal bugs at data boundaries.
Builtin concurrency (Chapter 18) features allow you to decompose problems into parts that you run separately and perhaps simultaneously. The language handles most of that for you.
Lazy lists and infinite lists allow you to process sequences without excessive copying or even having the entire list at one time (Chapter 6). You can easily create your own infinite lazy lists.
I could keep going, but you’ll run into more amazing features as you work your way through this book.
There will be times that you won’t want to use Perl 6. No language is the right tool for every job. If you like something else better or can finish a task faster with a different tool, more power to you! I hope, though, that this book helps you do what you need to do quickly and efficiently in Perl 6.
First Steps with the REPL
The REPL is a Read-Evaluate-Print-Loop tool that provides an interactive prompt. The REPL evaluates the code you type, shows you the result, then prompts you again. It’s a quick way to try out small snippets. When you run perl6 without arguments it starts its REPL:
% perl6
To exit type 'exit' or '^D'
>
The >
is the prompt that waits
for you to type something. When you type Return the REPL does its work.
Try it by adding two numbers:
%perl6
>2 + 2
4
If there’s an error it lets you know about it and prompts you again:
%perl6
>2 + Hamadryas
===SORRY!=== Error while compiling: Undeclared name: Hamadryas used at line 1 >
You don’t know why this failed yet because you’re at the beginning of the book. That doesn’t really matter as long as you know the REPL catches the error and gives you a new prompt. If you need to correct a mistake you should be able to use the up arrow to go back to the previous line (or further) to edit and rerun something.
Before you move on, you should know a few other tricks that can help you learn the geography of the language.
Note
When I write about methods in this book I generally preface them with the
method call dot so you know they’re methods, as in .is-prime
. The dot is not part of the
name.
A method is a label for predefined behavior of an object. Every object
has a type, and the
.^name
method tells you that
type:
%perl6
>3.^name
Int
The literal 3
is an object of
type Int
, for integer. Once you know what
type something is you can read its documentation to find out what you can
do with it.
Behavior is defined in classes
(Chapter 12), and these classes can be based on
more general classes through inheritance. You can use the .^mro
method to see
the inheritance chain (although the documentation also tells you):
%perl6
>3.^mro
((Int) (Cool) (Any) (Mu))
An object can do all the behavior of all the classes it inherits from. This shows
that 3
is an Int
, which is a Cool
(Convenient Object-Oriented Loop), which is an Any
(a base class for just about everything), which is, finally, a
Mu
(a thingy that is not
a thingy—think on that for awhile!).
Use .^methods
to see the list of methods for an object:
%perl6
>3.^methods
(Int Num Rat FatRat abs Bridge chr sqrt base polymod expmod is-prime floor ceiling round ...)
The type is also an object (a type object). It’s the abstract expression of the thingy without a concrete value. It has methods too:
%perl6
>Int.^methods
(Int Num Rat FatRat abs Bridge chr sqrt base polymod expmod is-prime floor ceiling round ...)
You can’t call many of those methods on a type object, though. You get an error because there’s no value yet:
%perl6
>Int.sqrt
Invocant of method 'sqrt' must be an object instance of type 'Int', not a type object of type 'Int'.
The methods .^name
, .^mro
, and .^methods
come from the language’s metaprogramming underpinnings. That’s a
bit advanced for this book given the number of pages I have, so you won’t
read more about that here.
Reading the Documentation
Now that you know about the REPL and how to find the type of an object, you probably want to read about those in the documentation. The p6doc program can do that:
% p6doc Int
... lots of text
If you want to know about a method you can add it to the type:
% p6doc Int.polymod
method polymod
Defined as:
method polymod(Int:D: +@mods)
Usage:
INTEGER.polymod(LIST)
...
Sometimes you don’t find the docs where you expect them. When that happens try one of the inherited classes:
% p6doc Int.sqrt
No documentation found for method 'sqrt'% p6doc Cool.sqrt
routine sqrt Defined as: sub sqrt(Numeric(Cool) $x) method sqrt() ...
I find myself mostly reading the docs online at https://docs.perl6.org. Worse than that, I Google something like “perl6 Int” and follow the first result. That site also has a handy search feature to help you find things without using a full text search. You can run the same site locally. Look for those details at the bottom of each page.
Basic Syntax
You often need to read code from the inside out, as you would a math formula, so that’s how I approach it here: starting from the very tiny and building up from there. This is a survey of the things you need to know and will read about in upcoming chapters. Don’t worry if you are a bit overwhelmed at this point. You’ll get used to these things as you practice.
Terms
At the lowest level a program has terms. These are the building blocks that form everything else. Think of these as the nouns of the language. Here are some terms:
2 e π 'Hello' $x now
These include literal data, such as 2
and 'Hello'
; variables, such as $x
; and defined symbols, such as π
. now
is a
term that represents the current time as an Instant
object.
A variable typically starts with a sigil—a special
character that denotes something about that variable. The variable
$x
has the $
sigil. Don’t worry about those just yet,
although you’ll see more later in this chapter.
Operators and Expressions
An expression is a combination of terms and operators that produce a new value. If the terms are the nouns, operators are the verbs that specify the action. They turn one or more terms into a new value. Operands are the values that an operator uses. A unary operator does something to a single operand:
- 137 # negate 137 to make -137 + '137' # convert the string '137' to a number $x++ # add 1 to the current value in $x
That #
and the text following
it is a comment (which you’ll see more about in a moment). It’s some
text that the program ignores and is a convenient way for you to leave
notes about your code. I’ll often use comments to reinforce a point or
show the output of an expression.
A binary operator works on two operands. Normally these operators show up between the operands (infixed):
2 + 2 # add two numbers $object.method() # the . method call operator $x = 137 # assign a value to a variable
A ternary
operator, such as the conditional operator, ??
!!
, has three operands:
$some_value ?? 'Yes' !! 'No' # choose one of two values
If the first thingy evaluates to True
, it selects the second thingy. Otherwise
it selects the third thingy. You’ll see more of these in Chapter 3.
Before, after, and around
Operators come in several varieties, with names that describe
their position and the number of operands they expect. You’ll see
these terms throughout the book. A prefix operator comes before its operand and usually takes only one operand.
The increment operator is an example. It adds one to the number in
$x
:
++$x
A postfix operator comes after its operand. There are increment forms of this type as well:
$x++
A circumfix operator surrounds its operand. Examples include the parentheses and the double quote marks:
( 1, 2, 3 ) "Hello"
A postcircumfix
operator surrounds its operand but comes after something else. A
single-element access to an Array
or a Hash
surrounds the index and comes
after the variable name. The []
and
<>
are the operators that
come after the name but surround the key:
@array[0] %hash<key>
Those terms are in the documentation. There are other ways you can arrange operators that don’t have standard terms, so I’ve fashioned my own that I don’t expect to use that much.
A precircumfix
operator surrounds an operand and comes before other operands. The
reduction operator (Chapter 6) surrounds an
operator that it places between each of the items that follow it. This
adds all the numbers without having to specify a +
between every pair:
[+] 1, 2, 3
A circumfix infix
operator surrounds an infix operator. The
hyperoperators <<>>
surround an operator and distribute that infix operator along the
two lists (Chapter 6):
(1, 2, 3) <<+>> (4, 5, 6)
There are other arrangements you might encounter in this book, but you can generally tell how they work by picking apart the name.
Operators are actually methods. Their names look a bit complicated because they start with the sort of operator they are and have the symbol in angle brackets:
infix:<+>(1, 2) # 3 my @array = 1, 2, 3 postcircumfix:<[ ]>( @array, 1 )
You won’t need these forms, but you should know that the operators figure out what to do based on the arguments.
Precedence
You can chain operations one after the other. Try this in the REPL:
1 + 2 + 3 + 4
The expression is evaluated in order of operator precedence and associativity. Precedence decides which operators go first and associativity figures out the order among operators of the same precedence (or even two of the same operator).
An operator’s precedence is relatively looser or tighter than other operators. With a
chain of terms the tighter operator goes first. Multiplication
(*
) happens before addition
(+
), just like in high school
algebra:
2 + 3 * 4 # 14
If you don’t like the order you can change it with parentheses. Things inside parentheses are computed before things outside. Another way to say that is that parentheses have the highest precedence. Now the addition happens first:
(2 + 3) * 4 # 20
If you have two operators of the same precedence then associativity decides the order of evaluation. Operators can be either left associative or right associative. The exponentiation operator is right associative, so the operation on the right happens first:
2 ** 3 ** 4 # 2.4178516392293e+24
It’s the same order as if you put explicit parentheses around the right two numbers:
2 ** (3 ** 4) # 2.4178516392293e+24
Use parentheses to make the left operation happen first:
(2 ** 3) ** 4 # 4096
Some operators can’t be combined and don’t have associativity. The range operator is one of the operators you can’t combine:
0 .. 5 # Range operator, nonassociative 0 .. 3 .. 5 # Illegal
Statements
A statement is a complete, standalone part of a program. An expression can be a
statement but it can also be part of a statement. Here’s a statement
using put
to output a message. It
adds a newline for you:
put 'Hello Perl 6!'
You separate statements with a semicolon. Here are two statements; they are on separate lines but you still need a semicolon between them:
put 'Hello Perl 6!'; put 'The time is ', now;
You don’t need the ;
unless
another statement follows, but I tend to put a semicolon at the end of
every statement because I know I’ll forget to add it when I add more
code:
put 'Hello Perl 6!'; put 'The time is ', now
Most whitespace is insignificant, which means you can use it how you like to format your program. These statements have a differently organized manner:
put 'Hello Perl 6!' ; put 'The time is ', now ;
There are a few situations where whitespace matters, but you’ll read about that when you need to know about it.
Blocks
A block (Chapter 5) combines one or more statements into a single unit by
surrounding them with a set of braces. Sometimes the block has a control keyword, such as
loop
, attached to it. This block
continually evaluates its statements until you stop the program with
Control-C. This is an infinite loop:
loop { state $count = 0; sleep 1; print $count++, "\r"; }
Each statement is separated by a semicolon and the last statement has a semicolon for good measure.
You don’t see a ;
after the
closing brace for that loop
, but it’s
implicitly there. A }
followed by
nothing more than whitespace until the end of the line implies a
;
. If you have more stuff on the same
line, though, you need a ;
after the
}
:
loop { ... }; put "Done";
The ...
(yada yada) operator is the way you signal that there’s something
there but you don’t care to say what it is at the moment. Use it when
you intend to fill in the details later. I’ll use those to hide code to
save space in examples. It compiles but gives you an error when you run
it. You’ll see this used throughout the book to shorten examples to fit
on the page.
A block creates a lexical scope. You can see what this scope is based on the position of the braces (hence, lexical). Things you define inside a scope only matter inside that scope and the deeper scopes it defines. This limits the effects of many things to exactly where you need them. The effects of variables and modules are limited to their lexical scope.
Comments
Comments are a
way to leave ourselves notes that the program doesn’t care
about. The compiler mostly ignores these things. You can make a comment
with a #
when the compiler
is expecting a new token. The compiler skips everything from that
#
to the end of the line. Here’s a
mostly useless comment:
put 'Hello Perl 6!'; # output a message
A better comment expounds on the purpose, not the effect, of the code. This type of little program is often used as a first exercise to check that everything is working. The comment can say that:
put 'Hello Perl 6!'; # show that the program ran
An alternative is an embedded
comment. Put your message inside the parentheses in #`( )
somewhere in your statement (or even
between statements):
put #`(Marketing asked for this) 'Hello Perl 6!';
This is a nice way to have multiline comments:
#`( * show that the program ran * need to add blockchain email AI feature ) put 'Hello Perl 6!';
Since a closing parenthesis ends the comment, you can’t have one in your comment.
Both of those are fine for short comments. Sometimes you want
to comment
out several lines to prevent them from running. If you put
the #
at the beginning of a line you
effectively remove that line from the program:
loop { state $count = 0; # sleep 1; print $count, "\r"; }
You might add another comment to remind yourself why that line is still in the code. Often programmers do this as they are debugging so they remember what was there before they started:
loop { state $count = 0; # Testing this for ticket 1234 (bug://1234) # I think that the sleep slows the program down too much # sleep 1; print $count, "\r"; }
Unspace
In most places Perl 6 doesn’t care about whitespace, but there are some parts of the Perl 6 syntax that don’t allow spaces. Space between the name of a subroutine and its opening parenthesis for an argument list changes the meaning:
my-sub 1, 2, 3; # three arguments my-sub( 1, 2, 3 ); # three arguments my-sub ( 1, 2, 3 ); # one argument (a List)
In that last line there’s a space between my-sub
and the (
. That compiles and runs, but instead of
three arguments the subroutine gets a single List
argument (Chapter 6). You can unspace that space with a backslash. Any whitespace following the \
is basically invisible to the
compiler:
my-sub\ (1, 2, 3 );
You might want to do this to format code into columns to make it easier to read:
my-sub\ ( 2, 4, 8 ); my-much-longer-name( 1, 3, 7 );
Objects and Classes
Perl 6 is a class-based object system. I’ll skip most of the theory of object-oriented programming (that could be a whole other book), but you should know that in these systems a class (Chapter 12) defines the abstract structure and behavior of an object. The object is a particular concrete version of that class.
Most of the data in Perl 6 are objects, and each object knows what
class defines it. Classes define methods, which are the behaviors of the
object. Classes can inherit
from another class to include its behavior, but they can also
include roles that
add behavior without inheritance. When you see class names in the
digital version of this book the name should link to the online
documentation for that class (for example, the Int
class).
You create objects by calling a constructor
method, often called .new
(Chapter 12). You pass arguments
to the method in parentheses after the method name:
my $fraction = Rat.new( 5, 4 );
There’s also a colon syntax for method arguments which relieves you from the burden of typing the closing parenthesis as long as there’s nothing more in the statement:
my $fraction = Rat.new: 5, 4;
Type objects represent the abstract idea of a class but aren’t objects. Sometimes they are useful as placeholders when you know what sort of object you want but you don’t know its value yet:
my $fraction = Rat;
With gradual typing you can restrict variables to fit into a type. These are runtime checks, so you don’t know that it didn’t work until you try it:
my Int $n;
Since you haven’t assigned a value to $n
yet, it’s an Int
type object. When you want to
assign a value it must match that type:
$n = 137; # works because it's an integer $n = 'Hamadryas'; # fails
Look through a class’s documentation to see what sorts of things its objects can do. In many of the exercises I’ll ask you to use a method that I haven’t shown you. This trains you to go to the docs, but also lets you learn things about seeing what’s out there. This saves some space in the book. Let’s try some of those now.
Variables
Perl 6 has named values. They can be immutable, which means you can’t change the values once you set them. They can also be mutable, which means you can change the values. The mutable ones are commonly called variables, but they are also known as containers. A container holds a value and you can replace that value with another. You’ll read more about that in the next chapter. Despite the possibility that you can’t change the value, I’ll still call all of these “variables.”
A named value has an identifier—a
fancy word for “name.” Names can include letters, digits, the underscore,
the hyphen, and the apostrophe ('
). You
must start your name with a letter or digit. These are valid
identifiers:
butterfly_name butterfly-name butterfly'name
The underscore, hyphen, or apostrophe can separate words to make them easier to read. Sometimes the underscore pattern is called snake case since the word separators crawl along the ground. The hyphen pattern is called kebab case (or sometimes lisp case).
Some people might feel more at home capitalizing the first letter of each word instead. This is known as camel case since it imitates the humps on a camel’s back. In this example there’s one hump, which is the best number of humps for a camel:
butterflyName
There are some rules with -
and
'
. You can’t have two -
or '
characters in a row, and the character after either must be a letter (not
a number). Also, you cannot start an identifier with these characters.
None of these are valid:
butterfly--name butterfly''name 'butterfly butterfly-1
A variable name combines a
sigil with an identifier. The sigil is a character that gives some context to the identifier. A
scalar is a single thingy. A scalar variable holds a single value and has a $
sigil. The $
looks similar to S
, for scalar:
$butterfly_name
As you encounter the different types you’ll encounter the other sigils. The
@
is for positionals (Chapter 6), the %
is for associatives (Chapter 9), and the
&
is for callables (Chapter 11).
The first time you use a variable you must declare it.
You do this so the compiler knows you definitely want to use that name and
to avoid problems with misspelling variables. The my
keyword declares the variable to be private to the current
scope:
my $number;
The next time you use $number
in
that same scope you don’t need to declare it. You probably want to assign
it a value. The =
is the assignment
operator:
$number = 137;
You initialize a variable first time you assign a value to it. You can do this at the same time that you declare it:
my $number = 137;
Since Perl 6 already knows which variables you intend to use it knows when you misspell one:
$numbear = 137;
You get an error that’s often aware enough to guess what you meant:
Variable '$numbear' is not declared. Did you mean '$number'?
Simple Output
To see what’s in a variable you can use (or “call”) the put
routine. This outputs the value to standard output and adds a newline to
the end:
put $number;
If you use say
it calls the .gist
method
for you. This often results in the same output, but some
complicated objects may summarize or elide data to give you something
easier to read. These two do the same thing:
say $number; put $number.gist;
If you don’t want to add a newline you can use print
:
print $number;
There are also method forms of each of these:
$number.put; $number.say; $number.print;
Lexical Scope
A variable is only visible in its lexical scope. If you define a variable inside braces you can’t use it outside the braces:
{ my $number = 137; } $number = 5; # a compilation error
This is caught when you try to compile the program:
Variable '$number' is not declared
A variable of the same name can exist in the outer scope and isn’t disturbed when the same name is reused in a deeper scope:
my $number = 5; put $number; { my $number = 137; put $number; } put $number;
These are two different variables that happen to use the same name. The compiler can tell them apart based on where you declared them. The inner scope declaration “hides” the outer scope one, so the result is:
5 137 5
Sometimes a named value doesn’t have a sigil. These sigilless variables don’t
create containers, which means that you can’t change their
values. This makes them handy for values you don’t want anyone to
accidentally change. Prefix the identifier with a \
:
my \magic-number = 42; magic-number.put;
These statements actually create terms, but since you declare them like variables it’s slightly easier to be a little wrong than pedantically correct.
Predefined Variables
Perl 6 defines several variables for you. These are prefixed with a sigil and then an additional character called a twigil. The combination of characters tells you something about the variable. Don’t worry about all the sorts of twigils that exist. Know that they do exist and that you can read about them at https://docs.perl6.org/language/variables or with p6doc:
% p6doc variables
The ?
twigil marks values that the compiler sets as it does its work.
These are compile-time variables. If
you want to know the file the compiler is working on you can look in
$?FILE
. The $
is the sigil and the ?
is the twigil:
put $?FILE;
The *
twigil marks dynamic
variables. These are looked up through the caller’s scope, but that’s not
the important part for this section. Your program automatically sets
these values. Some of them are about the environment of the
program:
%perl6
To exit type 'exit' or '^D' >$*EXECUTABLE
"/Applications/Rakudo/bin/perl6".IO >$*PROGRAM
"interactive".IO >$*USER
hamadryas >$*CWD
"/Users/hamadryas".IO
Others provide information about your version of Perl 6. This information might be useful if you need to report an issue:
>$*PERL
Perl 6 (6.c) >$*VM
moar (2018.04)
There are other dynamic variables for the standard filehandles. Each program
gets output, input, and error filehandles. The standard output (the default place where output goes) is
in $*OUT
and standard error is in $*ERR
.
These are IO::Handle
objects
and you can call .put
on them to make output:
$*OUT.put: 'Hello Hamadryas!'; $*ERR.put: 'Hello Hamadryas!';
Making and Running a Program
It’s time you wrote a program. That’s just a plain-text file that contains your source code. You don’t need any special software to create these files. They must be plain text though; word processors insert extra stuff and the compiler won’t tolerate that.
The first line in the program is typically the shebang line.
That’s a Unix thing that lets a text file pretend to be a program. When
you “run” the text file the system sees that the first two characters are
#!
. It uses the rest of that line as
the name of the program that will actually run the code. That’s the interpreter:
#!/Applications/Rakudo/bin/perl6
Your package (or custom installation) may have installed it somewhere else, in which case you’d use that path:
#!/usr/local/bin/perl6
Some people use env since that looks through your
PATH
to find the program:
#!/usr/bin/env perl6
Windows doesn’t know about shebangs, but it’s a good idea to include the shebang anyway since useful programs tend to escape into the world (life will find a way). For the rest of the book I’ll leave off the shebang line just to save space.
The rest of your file is your program. Here’s a common one that tests that you’ve probably done everything right. If you can run this program you’ve probably installed everything correctly:
put 'Hello World!';
Ensure your editor is set to encode your file as UTF-8. Save the file using any name that you like. perl6 doesn’t care about the name, although the docs suggest a .p6 or .pl6 extension.
Run your program from the command line:
% perl6 hello-world.p6
When you do this perl6 first compiles the program. It sees all of your program text and parses it. That’s the compile time part of the process. If it finds no problem it then runs what it has already compiled.
If you want to check your program without running it you can use the
-c
switch. This is a syntax
check:
% perl6 -c hello-world.p6
Most errors at this point are syntax errors; you wrote a program that Perl 6 couldn’t parse.
Summary
You’ve seen the basic structure of a program and how you build up a program from smaller elements. You wrote some very small programs. You have some insights into the documentation; you’ll get more practice with that throughout your programming career. Now the trick is to make slightly larger programs.
Get Learning Perl 6 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.