General rules of Perl 6 syntax

Perl 6 borrows many concepts from human language. Which is not surprising, considering it was designed by a linguist.

It reuses common elements in different contexts, has the notion of nouns (terms) and verbs (operators), is context-sensitive (in the every day sense, not necessarily in the Computer Science interpretation), so a symbol can have a different meaning depending on whether a noun or a verb is expected.

It is also self-clocking, so that the parser can detect most of the common errors and give good error messages.

Lexical Conventions

Perl 6 code is Unicode text, current implementations support UTF-8 as the input encoding.

See also Unicode versus Texas symbols.

Free Form

It is free-form, in the sense that you are mostly free to chose the amount of whitespace you chose, though in some cases, the presence or absence of whitespace carries meaning.

So you can write

if True {
    say "Hello";


    if True {
say "Hello";


if True { say "Hello" }

or even

if True {say "Hello"}

though you can't leave out any of the remaining whitespace.


In many places where the compiler would not allow a space you can use any whitespace that is quoted with a backslash. Unspaces in tokens are not supported. Newlines that are unspaced still count when the compiler produces line numbers. Use cases for unspace are separation of postfix operators and routine argument lists.

sub alignment(+@l{ +@l };
sub long-name-alignment(+@l{ +@l };
alignment\         (1,2,3,4).say;
long-name-alignment(3,5)\   .say;

Separating Statements

A Perl 6 program is a list of statements, separated by semicolons ;. A semicolon after the final statement (or after the final statement inside a block) is optional, though it's good form to include it.

A closing curly brace followed by a newline character implies a statement separator, which is why you don't need to write a semicolon after an if statement block.

if True {
    say "Hello";
say "world";

Both semicolons are optional here, but leaving them out increases the chance of syntax errors when adding more lines later.

You do need to include a semicolon between the if block and the say statement if you want them all on one line.

if True { say "Hello" }say "world";
#                     ^^^ this ; is required 


Comments are parts of the program text only intended for human readers, and the Perl 6 compilers does not evaluate them as program text.

Comments count as whitespace in places where the absence or presence of whitespace disambiguates possible parses.

Single-line comments

The most common form of comments in Perl 6 starts with a single hash character # and goes until the end of the line.

if $age > 250 {     # catch obvious outliers 
    # this is another comment! 
    die "That doesn't look right"

Multi-line / embedded comments

Multi-line and embedded comments start with a hash character, followed by a backtick, and then some opening bracketing character, and end with the matching closing bracketing character. The content can not only span multiple lines, but can also be embedded inline.

if #`( why would I ever write an inline comment here? ) True {
    say "something stupid";

Brackets inside the comment can be nested, so in #`{ a { b } c }, the comment goes until the very end of the string. You may also use more complex brackets, such as #`{{ double-curly-brace }}, which might help disambiguate from nested brackets.

Pod comments

Pod syntax can be used for multi-line comments

say "this is code";
=begin comment
Here are several
of comment
=end comment
say 'code again';


Identifiers are a grammatical building block that occur in several places. An identifier is a primitive name, and must start with an alphabetic character (or an underscore), followed by zero or more word characters (alphabetic, underscore or number). You can also embed dashes - or single quotes ' in the middle, but not two in a row, and only if followed immediately by an alphabetic character.

# valid identifiers: 
# not valid identifiers: 

Names of constants, types (including classes and modules) and routines (subs and methods) are identifiers, and they also appear in variable names (usually proceeded by a sigil; see variables for more details.)

Namespaces are provided by packages. By separating identifiers with double colons, the right most name is inserted into existing or automatically created packages.

my Int $Foo::Bar::buzz = 42;
dd $Foo::Bar::buzz# OUTPUT: «Int $v = 42␤» 

Identifiers can contain colon pairs. The entire colon pair becomes part of the name of the identifier.

my $foo:bar = 1;
my $foo:bar<2> = 2;
dd MY::.keys;
# OUTPUT: «("\$=pod", "!UNIT_MARKER", "EXPORT", "\$_", "\$!", "::?PACKAGE", 
#          "GLOBALish", "\$¢", "\$=finish", "\$/", "\$foo:bar<1>", "\$foo:bar<2>", 
#          "\$?PACKAGE").Seq␤» 

Colon pairs in identifiers support interpolation. Please note that resolution of names often happens at compile time, so interpolation values must be known at compile time.

constant $c = 42;
my $a:foo<42> = "answer";
say $a:foo«$c»;
# OUTPUT: «answer␤» 

Unicode superscript numerals are exponents and not part of an identifier; e.g. $x² does the square of variable $x. Subscript numerals are TBD.

Term term:<>

To introduce identifiers that would defy the rules of normal names of identifiers use term:<>.

use Testplan 1constant &term:<👍> = &ok.assuming(True);
# OUTPUT: «1..1␤ok 1 - ␤» 

Statements and Expressions

Perl 6 programs are made of lists of statements. A special case of a statement is an expression, which returns a value. For example if True { say 42 } is syntactically a statement, but not an expression, whereas 1 + 2 is an expression (and thus also a statement).

The do prefix turns statements into expressions. So while

my $x = if True { 42 };     # Syntax error! 

is an error,

my $x = do if True { 42 };

assigns the return value of the if statement (here 42) to the variable $x.


Terms are the basic nouns that, optionally together with operators, can form expressions. Examples for terms are variables ($x), barewords such as type names (Int), literals (42), declarations (sub f() { }) and calls (f()).

For example, in the expression 2 * $salary, 2 and $salary are two terms (an integer literal and a variable).


Variables typically start with a special character called the sigil, and are followed by an identifier. Variables must be declared before you can use them.

# declaration: 
my $number = 21;
# usage: 
say $number * 2;

See the documentation on variables for more details.

Barewords (Constants, Type Names)

Pre-declared identifiers can be terms on their own. Those are typically type names or constants, but also the term self which refers to an object that a method was called on (see objects), and sigilless variables:

say Int;                # OUTPUT: «(Int)␤» 
#   ^^^ type name (built in) 
constant answer = 42;
say answer;
#   ^^^^^^ constant 
class Foo {
    method type-name {
      # ^^^^ built-in term 'self' 
say Foo.type-name;     # OUTPUT: «Foo␤» 
#   ^^^ type name 

Packages and Qualified Names

Named entities, such as variables, constants, classes, modules, subs, etc, are part of a namespace. Nested parts of a name use :: to separate the hierarchy. Some examples:

$foo                # simple identifiers 
$Foo::Bar::baz      # compound identifiers separated by :: 
$Foo::($bar)::baz   # compound identifiers that perform interpolations 
Foo::Bar::bob(23)   # function invocation given qualified name 

See the documentation on packages for more details.


A literal is a representation of a constant value in source code. Perl 6 has literals for several built-in types, like strings, several numeric types, pairs and more.

String literals

String literals are surrounded by quotes:

say 'a string literal';
say "a string literal\nthat interprets escape sequences";

See quoting for many more options.

Number literals

Number literals are generally specified in base ten, unless a prefix like 0x (hexadecimal, base 16), 0o (octal, base 8) or 0b (binary, base 2) or an explicit base in adverbial notation like :16<A0> specifies it otherwise. Unlike other programming languages, leading zeros do not indicate base 8; instead a compile-time warning is issued.

In all literal formats, you can use underscores to group digits; they don't carry any semantic information; the following literals all evaluate to the same number:


Int literals

Integers default to signed base-10, but you can use other bases. For details, see Int.

-2          # actually not a literal, but unary - operator applied to numeric literal 2 
0xBEEF      # base 16 
0o755       # base 8 
:3<1201>    # arbitrary base, here base 3 

Rat literals

Rat literals (rationals) are very common, and take the place of decimals or floats in many other languages. Integer division also results in a Rat.

-2.5        # Not actually a literal, but still a Rat 
:3<21.0012> # Base 3 rational 
2/3         # Not actually a literal, but still a Rat 

Num literals

Scientific notation with an integer exponent to base ten after an e produces floating point number:

2e2.5       # error 

Complex literals

Complex numbers are written either as an imaginary number (which is just a rational number with postfix i appended), or as a sum of a real and an imaginary number:

6.123e5i    # note that this is 6.123e5 * i and not 6.123 * 10 ** (5i) 

Pair literals

Pairs are made of a key and a value, and there are two basic forms for constructing them: key => 'value' and :key('value').

Arrow pairs

Arrow pairs can have an expression or an identifier on the left-hand side:

identifier => 42
"identifier" => 42
('a' ~ 'b'=> 1

Adverbial pairs (colon pairs)

Short forms without explicit values:

my $thing = 42;
:$thing                 # same as  thing => $thing 
:thing                  # same as  thing => True 
:!thing                 # same as  thing => False 

The variable form also works with other sigils, like :&callback or :@elements.

Long forms with explicit values:

:thing($value)              # same as  thing => $value 
:thing<quoted list>         # same as  thing => <quoted list> 
:thing['some''values']    # same as  thing => ['some', 'values'] 
:thing{=> 'b'}            # same as  thing => { a => 'b' } 

Array literals

A pair of square brackets can surround an expression to form an itemized Array literal; typically there is a comma-delimited list inside:

say ['a''b'42].join(' ');   # OUTPUT: «a b 42␤» 
#   ^^^^^^^^^^^^^^ Array constructor 

The array constructor flattens non-itemized arrays and lists, but not itemized arrays themselves:

my @a = 12;
# flattens: 
say [@a34].elems;       # OUTPUT: «4␤» 
# does not flatten: 
say [[@a], [34]].elems;   # OUTPUT: «2␤» 

Hash literals

A pair of curly braces can surround a list of pairs to form a Hash literal; typically there is a comma-delimited list of pairs inside. If a non-pair is used, it is assumed to be a key and the next element is the value. Most often this is used with simple arrow pairs.

say { => 3=> 23:foo:dog<cat>"french""fries" };
# OUTPUT: «a => 3, b => 23, dog => cat, foo => True, french => fries␤» 
say {=> 73foo => "fish"}.keys.join(" ");   # OUTPUT: «a foo␤» 
#   ^^^^^^^^^^^^^^^^^^^^^^^^ Hash constructor 

When assigning to a % sigil variable, the curly braces are optional.

my %ages = fred => 23jean => 87ann => 4;

By default keys in { } are forced to strings. To compose a hash with non-string keys, use a colon prefix:

my $when = :{ (now=> "Instant", (> "DateTime" };

Note that with objects as keys, you cannot access non-string keys as strings:

:{ -1 => 410 => 421 => 43 }<0>;  # OUTPUT: «Any␤» 
:{ -1 => 410 => 421 => 43 }{0};  # OUTPUT: «42␤» 

Regex literals

A Regex is declared with slashes like /foo/. Note that this // syntax is shorthand for the full rx// syntax.

/foo/          # Short version 
rx/foo/        # Longer version 
Q :regex /foo/ # Even longer version
my $r = /foo/; # Regexes can be assigned to variables

Signature literals

Signatures can be used standalone for pattern matching, in addition to the typical usage in sub and block declarations. A standalone signature is declared starting with a colon:

say "match!" if 5"fish" ~~ :(IntStr); # OUTPUT: «match!␤» 
my $sig = :(Int $aStr);
say "match!" if (5"fish"~~ $sig# OUTPUT: «match!␤» 
given "foo"42 {
  when :(StrStr{ "This won't match" }
  when :(StrInt $n where $n > 20{ "This will!" }

See the Signatures documentation for more about signatures.


Variable declaration

my $x;                          # simple lexical variable 
my $x = 7;                      # initialize the variable 
my Int $x = 7;                  # declare the type 
my Int:D $x = 7;                # specify that the value must be defined (not undef) 
my Int $x where { $_ > 3 } = 7# constrain the value based on a function 
my Int $x where * > 3 = 7;      # same constraint, but using L<Whatever> short-hand 

See Variable Declarators and Scope for more details on other scopes (our, has).

Subroutine declaration

# The signature is optional 
sub foo { say "Hello!" }
sub say-hello($to-whom{ say "Hello $to-whom!" }

You can also assign subroutines to variables.

my &f = sub { say "Hello!" } # Un-named sub 
my &f = -> { say "Hello!" }  # Lambda style syntax. The & sigil indicates the variable holds a function 
my $f = -> { say "Hello!" }  # Functions can also be put into scalars 

Module, Class, Role, and Grammar declaration

There are several types of compilation units (packages), each declared with a keyword, a name, some optional traits, and a body of functions.

module Gar { }
class Foo { }
role Bar { }
grammar Baz { }

You can declare a unit of things without explicit curly brackets.

unit module Gar;
# ... stuff goes here instead of in {}'s 

Multi-dispatch declaration

See also Multi-dispatch.

Subroutines can be declared with multiple signatures.

multi sub foo() { say "Hello!" }
multi sub foo($name{ say "Hello $name!" }

Inside of a class, you can also declare multi-dispatch methods.

multi method greet { }
multi method greet(Str $name{ }

Subroutine calls

See functions.

foo;   # Invoke the function foo with no arguments 
foo(); # Invoke the function foo with no arguments 
&f();  # Invoke &f, which contains a function 
&f.(); # Same as above, needed to make the following work 
my @functions = ({say 1}{say 2}{say 3});
# Method invocation. Object (instance) is $person, method is set-name-age 
$person.set-name-age('jane'98);  # Most common way 
$person.set-name: 'jane'98;      # Precedence drop 
set-name($person: 'jane'98);     # Invocant marker 


See Operators for lots of details.

Operators are functions with a more symbol heavy and composable syntax. Like other functions, operators can be multi-dispatch to allow for context-specific usage.

There are five types (arrangements) for operators, each taking either one or two arguments.

++$x           # prefix, operator comes before single input 
5 + 3          # infix, operator is between two inputs 
$x++           # postfix, operator is after single input 
<the blue sky> # circumfix, operator surrounds single input 
%foo<bar>      # postcircumfix, operator comes after first input and surrounds second 

Meta Operators

Operators can be composed. A common example of this is combining an infix (binary) operator with assignment. You can combine assignment with any binary operator.

$x += 5     # Adds 5 to $x, same as $x = $x + 5 
$x min= 3   # Sets $x to the smaller of $x and 3, same as $x = $x min 3 
$x .= child # Equivalent to $x = $x.child 

Wrap an infix operator in [ ] to create a new reduction operator that works on a single list of inputs, resulting in a single value.

[+] <1 2 3 4 5>;        # OUTPUT: «15␤» 
(((1 + 2+ 3+ 4+ 5 # equivalent expanded version 

Wrap an infix operator in « » (or the ASCII equivalent ) to create a new hyper operator that works pairwise on two lists.

<1 2 3> «+» <4 5 6> # OUTPUT: «<5 7 9>␤» 

The direction of the arrows indicates what to do when the lists are not the same size.

@a «+« @b # Result is the size of @b, elements from @a will be re-used 
@a »+» @b # Result is the size of @a, elements from @b will be re-used 
@a «+» @b # Result is the size of the biggest input, the smaller one is re-used 
@a »+« @b # Exception if @a and @b are different sizes 

You can also wrap a unary operator with a hyper operator.

 <1 2 3> # OUTPUT: «<-1 -2 -3>␤»