Perl 5 to Perl 6, in a nutshell: How do I do what I used to do?

This page attempts to index the changes in syntax and semantics from Perl 5 to Perl 6. Whatever worked in Perl 5 and must be written differently in Perl 6, should be listed here (whereas many new Perl 6 features and idioms won't be).

Hence this should not be mistaken for a beginner tutorial or a promotional overview of Perl 6; it is intended as a technical reference for Perl 6 learners with a strong Perl 5 background and for anyone porting Perl 5 code to Perl 6 (though note that Automated Translation might be more convenient).

A note on semantics; when we say "now" in this document, we mostly just mean "now that you are trying out Perl 6." We don't mean to imply that Perl 5 is now suddenly obsolete. Quite the contrary, most of us love Perl 5, and we expect Perl 5 to continue in use for a good many years. Indeed, one of our more important goals has been to make interaction between Perl 5 and Perl 6 run smoothly. However, we do also like the design decisions in Perl 6, which are certainly newer and arguably better integrated than many of the historical design decisions in Perl 5. So many of us do hope that over the next decade or two, Perl 6 will become the more dominant language. If you want to take "now" in that future sense, that's okay too. But we're not at all interested in the either/or thinking that leads to fights.


See https://modules.perl6.org/ .

If the module that you were using has not been converted to Perl 6, and no alternative is listed in this document, then its use under Perl 6 may not have been addressed yet.

There are multiple projects aiming to make it possible to use Perl 5 modules directly from Perl 6 code:

v5 A slang that lets Rakudo itself parse blocks of Perl 5 code, and compile them to the same bytecode that it compiles Perl 6 code to.

Inline::Perl5 Uses an embedded instance of the perl interpreter to run Perl 5 code called from your Perl 6 script.

Of these, Inline::Perl5 is currently the furthest along and the most promising.



In identifiers, Perl 6 allows the use of dashes (-), underscores (_), apostrophes ('), and alphanumerics:

sub test-doesn't-hang { ... }
my $ความสงบ = 42;
my \Δ = 72; say 72 - Δ;

-> Method calls

If you've read any Perl 6 code at all, it's immediately obvious that method call syntax now uses a dot instead of an arrow:

$person->name  # Perl 5
$person.name   # Perl 6

The dot notation is both easier to type and more of an industry standard. But we also wanted to steal the arrow for something else. (Concatenation is now done with the ~ operator, if you were wondering.)

To call a method whose name is not known until runtime:

$object->$methodname(@args);  # Perl 5
$object."$methodname"(@args); # Perl 6

If you leave out the quotes, then Perl 6 expects $methodname to contain a Method object, rather than the simple string name of the method.


Perl 5 allows a surprising amount of flexibility in the use of whitespace, even with strict mode and warnings turned on:

# unidiomatic but valid Perl 5
say"Hello ".ucfirst  ($people
    [$ i]

Perl 6 also endorses programmer freedom and creativity, but balanced syntactic flexibility against its design goal of having a consistent, deterministic, extensible grammar that supports single-pass parsing and helpful error messages, integrates features like custom operators cleanly, and doesn't lead programmers to accidentally misstate their intent. Also, the practice of "code golf" is slightly de-emphasized; Perl 6 is designed to be more concise in concepts than in keystrokes.

As a result, there are various places in the syntax where whitespace is optional in Perl 5, but is either mandatory or forbidden in Perl 6. Many of those restrictions are unlikely to concern much real-life Perl code (e.g., whitespace being disallowed between the sigil and name of a variable), but there are a few that will unfortunately conflict with some Perl hackers' habitual coding styles:

However, note that you can use unspace to add whitespace in Perl 6 code in places where it is otherwise not allowed:

# Perl 5
my @books = $xml->parse_file($file)          # some comment

# Perl 6
my @books = $xml.parse-file($file)\          # some comment

See also S03#Minimal whitespace DWIMmery and S04#Statement parsing in the Perl 6 design docs.


In Perl 5, arrays and hashes use changing sigils depending on how they are being accessed. In Perl 6 the sigils are invariant, no matter how the variable is being used - you can think of them as part of the variable's name.

(See also Dereferencing).

$ Scalar

The $ sigil is now always used with "scalar" variables (e.g. $name), and no longer for array indexing and Hash indexing. That is, you can still use $x[1] and $x{"foo"}, but it will act on $x, with no effect on a similarly named @x or %x. Those would now be accessed with @x[1] and %x{"foo"}.

@ Array

The @ sigil is now always used with "array" variables (e.g. @months, @months[2], @months[2, 4]), and no longer for value-slicing hashes.

% Hash

The % sigil is now always used with "hash" variables (e.g. %calories, %calories<apple>, %calories<pear plum>), and no longer for key/value-slicing arrays.

& Sub

The & sigil is now used consistently (and without the help of a backslash) to refer to the function object of a named subroutine/operator without invoking it, i.e. to use the name as a "noun" instead of a "verb":

my $sub = \&foo; # Perl 5
my $sub = &foo;  # Perl 6

callback => sub { say @_ }  # Perl 5 - can't pass built-in sub directly
callback => &say            # Perl 6 - & gives "noun" form of any sub

Since Perl 6 does not allow adding/removing symbols in a lexical scope once it has finished compiling, there is no equivalent to Perl 5's undef &foo;, and the closest equivalent to Perl 5's defined &foo would be defined &::("foo") (which uses the "dynamic symbol lookup" syntax). However, you can declare a mutable named subroutine with my &foo; and then change its meaning at runtime by assigning to &foo.

In Perl 5, the ampersand sigil can additionally be used to call subroutines in special ways with subtly different behavior compared to normal sub calls. In Perl 6 those special forms are no longer available:

* Glob

In Perl 5, the * sigil referred to the GLOB structure that Perl uses to store non-lexical variables, file handles, subs, and formats.

(This should not be confused with the Perl 5 built-in glob() function, which reads filenames from a directory).

You are most likely to encounter a GLOB in code written on a early Perl version that does not support lexical filehandles, when a filehandle needed to be passed into a sub.

# Perl 5 - ancient method
sub read_2 {
    local (*H) = @_;
    return scalar(<H>), scalar(<H>);
open FILE, '<', $path or die;
my ($line1, $line2) = read_2(*FILE);

You should refactor your Perl 5 code to remove the need for the GLOB, before translating into Perl 6.

# Perl 5 - modern use of lexical filehandles
sub read_2 {
    my ($fh) = @_;
    return scalar(<$fh>), scalar(<$fh>);
open my $in_file, '<', $path or die;
my ($line1, $line2) = read_2($in_file);

And here's just one possible Perl 6 translation:

# Perl 6
sub read-n($fh, $n) {
    return $fh.get xx $n;
my $in-file = open $path or die;
my ($line1, $line2) = read-n($in-file, 2);

[] Array indexing/slicing

Index and slice operations on arrays no longer inflect the variable's sigil, and adverbs can be used to control the type of slice:

Also note that the subscripting brackets are now a normal postcircumfix operator rather than a special syntactic form, and thus checking for existence of elements and unsetting elements is done with adverbs.

{} Hash indexing/slicing

Index and slice operations on hashes no longer inflect the variable's sigil, and adverbs can be used to control the type of slice. Also, single-word subscripts are no longer magically autoquoted inside the curly braces; instead, the new angle-brackets version is available which always autoquotes its contents (using the same rules as the qw// quoting construct):

Also note that the subscripting curly braces are now a normal postcircumfix operator rather than a special syntactic form, and thus checking for existence of keys and removing keys is done with adverbs.

Reference creation

In Perl 5, references to anonymous arrays and hashes and subs are returned during their creation. References to existing named variables and subs were generated with the \ operator.

In Perl 6, anonymous arrays and hashes and subs still return their reference during creation. References to named subs are generated by preceding the sub name with a & sigil. References to existing named variables are generated by item context.

my $aref = [ 1, 2, 9 ];          # Both Perl 5&6
my $href = { A => 98, Q => 99 }; # Both Perl 5&6 [*See Note*]

my $aref =     \@aaa  ; # Perl 5
my $aref = item(@aaa) ; # Perl 6

my $href =     \%hhh  ; # Perl 5
my $href = item(%hhh) ; # Perl 6

my $sref =     \&foo  ; # Perl 5
my $sref =      &foo  ; # Perl 6

NOTE: If one or more values reference the topic variable, $_, the right-hand side of the assignment will be interpreted as a Block, not a Hash:

my @people = [
    { id => "1A", firstName => "Andy", lastName => "Adams" },
    { id => "2B", firstName => "Beth", lastName => "Burke" },
    # ...

sub lookup-user (Hash $h) { #`(Do something...) $h }

my @names = map {
    my $query = { name => "$_<firstName> $_<lastName>" };
    say $query.WHAT;       # (Block)
    say $query<name>;      # ERROR: Type Block does not support associative indexing

    lookup-user($query);   # Type check failed in binding $h; expected Hash but got Block
}, @people;

Instead, you should either:

See Hash assignment for more details.


In Perl 5, the syntax for dereferencing an entire reference is the type-sigil and curly braces, with the reference inside the curly braces.

In Perl 6, the curly braces are changed to parentheses.

# Perl 5
    say      ${$scalar_ref};
    say      @{$arrayref  };
    say keys %{$hashref   };
    say      &{$subref    };

# Perl 6
    say      $($scalar_ref);
    say      @($arrayref  );
    say keys %($hashref   );
    say      &($subref    );

Note that in both Perl 5 and Perl 6, the surrounding curly braces or parentheses can often be omitted, though the omission can reduce readability.

In Perl 5, the arrow operator, -> , is used for single access to a composite's reference or to call a sub through its reference. In Perl 6, we now use the dot operator . for those tasks.

# Perl 5
    say $arrayref->[7];
    say $hashref->{'fire bad'};
    say $subref->($foo, $bar);

# Perl 6
    say $arrayref.[7];
    say $hashref.{'fire bad'};
    say $subref.($foo, $bar);

In recent versions of Perl 5 (5.20 and later), a new feature allows the use of the arrow op for dereferencing. See http://search.cpan.org/~shay/perl-5.20.1/pod/perl5200delta.pod#Experimental_Postfix_Dereferencing That new feature corresponds Perl 6 .list and .hash methods:

# Perl 5.20
    use experimental qw< postderef >;
    my @a = $arrayref->@*;
    my %h = $hashref->%*;
    my @slice = $arrayref->@[3..7];

# Perl 6
    my @a = $arrayref.list;         # or @($arrayref)
    my %h = $hashref.hash;          # or %($hashref)
    my @slice = $arrayref[3..7];

The "Zen" slice does the same thing:

# Perl 6
    my @a = $arrayref[];
    my %h = $hashref{};

See S32/Containers


See S03/Operators for full details on all operators.


<=> cmp Three-way comparisons

In Perl 5, these operators returned -1, 0, or 1. In Perl 6, they return Order::Less, Order::Same, or Order::More.

cmp is now named leg; it forces string context for the comparison.

<=> still forces numeric context.

cmp in Perl 6 does either <=> or leg, depending on the existing type of its arguments.

~~ Smart-match operator

While the operator has not changed, the rules for what exactly is matched depends on the types of both arguments, and those rules are far from identical in Perl 5 and Perl 6. See S03/Smart matching

& | ^ String Bitwise ops

& | ^ Numeric Bitwise ops

& | ^ Boolean ops

In Perl 5, & | ^ were invoked according to the contents of their arguments. For example, 31 | 33 returns a different result than "31" | "33".

In Perl 6, those single-character ops have been removed, and replaced by two-character ops which coerce their arguments to the needed context.

# Infix ops (two arguments; one on each side of the op)
+&  +|  +^  And Or Xor: Numeric
~&  ~|  ~^  And Or Xor: String
?&  ?|  ?^  And Or Xor: Boolean

# Prefix ops (one argument, after the op)
+^  Not: Numeric
~^  Not: String
?^  Not: Boolean (same as the ! op)

<< >> Numeric shift left|right ops

Replaced by +< and +> .

say 42 << 3; # Perl 5
say 42 +< 3; # Perl 6

=> Fat comma

In Perl 5, => acted just like a comma, but also quoted its left-hand side.

In Perl 6, => is the Pair operator, which is quite different in principle, but works the same in many situations.

If you were using => in hash initialization, or in passing arguments to a sub that expects a hashref, then the usage is likely identical.

# Works in Perl 5 and Perl 6
my %hash = ( AAA => 1, BBB => 2 );
get_the_loot( 'diamonds', { quiet_level => 'very', quantity => 9 }); # Note the curly braces

If you were using => as a convenient shortcut to not have to quote part of a list, or in passing arguments to a sub that expects a flat list of KEY, VALUE, KEY, VALUE, then continuing to use => may break your code. The easiest workaround is to change the fat comma to a regular comma, and manually add quotes to its left-hand side. Or, you can change the sub's API to slurp a hash. A better long-term solution is to change the sub's API to expect Pairs. However, this requires you to change all sub calls at once.

# Perl 5
sub get_the_loot {
    my $loot = shift;
    my %options = @_;
    # ...
# Note: no curly braces in this sub call
get_the_loot( 'diamonds', quiet_level => 'very', quantity => 9 );
# Perl 6, original API
sub get_the_loot( $loot, *%options ) { # The * means to slurp everything
get_the_loot( 'diamonds', quiet_level => 'very', quantity => 9 ); # Note: no curly braces in this API

# Perl 6, API changed to specify valid options
# The colon before the sigils means to expect a Pair,
# with the key having the same name as the variable.
sub get_the_loot( $loot, :$quiet_level?, :$quantity = 1 ) {
    # This version will check for unexpected arguments!
get_the_loot( 'diamonds', quietlevel => 'very' ); # Throws error for misspelled parameter name

? : Ternary operator

Now spelled with two question marks instead of one question mark, and two exclamation points instead of one colon.

my $result = ( $score > 60 )  ? 'Pass'  : 'Fail'; # Perl 5
my $result = ( $score > 60 ) ?? 'Pass' !! 'Fail'; # Perl 6

. (Dot op) Concatenation

Replaced by the tilde.

Mnemonic: think of "stitching" together the two strings with needle and thread.

$food = 'grape' . 'fruit'; # Perl 5
$food = 'grape' ~ 'fruit'; # Perl 6

x List Repeat op or String Repeat op

In Perl 5, x was the Repetition operator.

In scalar context, x would repeat a string. In Perl 6, x repeats strings in any context.

In list context, x would repeat a list—but only if the left argument is parenthesized! In Perl 6, the new xx op repeats lists in any context.

Mnemonic: x is short and xx is long, so xx is the one used for lists.

# Perl 5
    print '-' x 80;             # Print row of dashes
    @ones = (1) x 80;           # A list of 80 1's
    @ones = (5) x @ones;        # Set all elements to 5
# Perl 6
    print '-' x 80;             # Unchanged
    @ones = 1 xx 80;            # Parentheses no longer needed
    @ones = 5 xx @ones;         # Parentheses no longer needed

.. ... Two Dots or Three Dots, Range op or Flipflop op

In Perl 5, .. was one of two completely different operators, depending on context.

In list context, .. is the familiar range operator. Range has many new wrinkles in Perl 6, but ranges from Perl 5 code should not require translation.

In scalar context, .. and ... were the little-known Flipflop operators. They have been replaced by ff and fff.

String interpolation

In Perl 5, "${foo}s" deliminates a variable name from regular text next to it. In Perl 6, simply extend the curly braces to include the sigil too: "{$foo}s"

Compound Statements


if elsif else unless

Mostly unchanged; parentheses around the conditions are now optional, but if used, must not immediately follow the keyword, or it will be taken as a function call instead. Binding the conditional expression to a variable is also a little different:

if (my $x = dostuff()) {...}  # Perl 5
if dostuff() -> $x {...}      # Perl 6

(You can still use the my form in Perl 6, but it will scope to the outer block, not the inner.)

The unless conditional only allows for a single block in Perl 6; it does not allow for an elsif or else clause.


The given-when construct is like a chain of if-elsif-else statements or like the switch-case construct in e.g. C. It has the general structure:

given EXPR {
    when EXPR { ... }
    when EXPR { ... }
    default { ... }

In its simplest form, the construct is as follows:

given $value {
    when "a match" {
    when "another match" {
    default {

This is simple in the sense that a scalar value is matched in the when statements. More generally, the matches are actually smart-matches on the input value such that lookups using more complex entities such as regexps can be used instead of scalar values.

See also the warnings on the smart-match op above.


while until

Mostly unchanged; parentheses around the conditions are now optional, but if used, must not immediately follow the keyword, or it will be taken as a function call instead. Binding the conditional expression to a variable is also a little different:

while (my $x = dostuff()) {...}  # Perl 5
while dostuff() -> $x {...}      # Perl 6

(You can still use the my form in Perl 6, but it will scope to the outer block, not the inner.)

Note that reading line-by-line from a filehandle has changed.

In Perl 5, it was done in a while loop using the diamond operator. Using for instead of while was a common bug, because the for causes the whole file to be sucked in at once, swamping the program's memory usage.

In Perl 6, for statement is lazy, so we read line-by-line in a for loop using the .lines method.

while (<IN_FH>)  { } # Perl 5
for $IN_FH.lines { } # Perl 6

do while/until

do {
} while $x < 10;

do {
} until $x >= 10;

The construct is still present, but do was renamed to repeat, to better represent what the construct does:

repeat {
} while $x < 10;

repeat {
} until $x >= 10;

for foreach

Note first this common misunderstanding about the for and foreach keywords. Many programmers think that they distinguish between the C-style three-expression form and the list-iterator form; they do not! In fact, the keywords are interchangeable; the Perl 5 compiler looks for the semi-colons within the parentheses to determine which type of loop to parse.

The C-style three-factor form now uses the loop keyword, and is otherwise unchanged. The parentheses *are* still required.

for  ( my $i = 1; $i <= 10; $i++ ) { ... } # Perl 5
loop ( my $i = 1; $i <= 10; $i++ ) { ... } # Perl 6

The loop-iterator form of for or foreach is named for in Perl 6. foreach is no longer a keyword. Parentheses are optional.

The iteration variable, if any, has been moved from before the list, to after the list and an added arrow operator.

The iteration variable is now always lexical; my is neither needed nor allowed.

In Perl 5, the iteration variable is a read-write alias to the current list element.

In Perl 6, that alias is read-only (for safety), unless you change -> to <->. When translating, inspect the use of the loop variable to decide if read-write is needed.

for my $car (@cars)  {...} # Perl 5; read-write
for @cars  -> $car   {...} # Perl 6; read-only
for @cars <-> $car   {...} # Perl 6; read-write

If the default topic $_ is being used, but needs to be read-write, then just use <-> and explicitly specify $_.

for (@cars)      {...} # Perl 5; default topic
for @cars        {...} # Perl 6; $_ is read-only
for @cars <-> $_ {...} # Perl 6; $_ is read-write


Here is the equivalent to Perl 5’s while…each(%hash) or while…each(@array) (= iterating over both the keys or indices and values of a data structure) in Perl 6:

while (my ($i, $v) = each(@array)) { ... } # Perl 5
for @array.kv -> $i, $v { ... } # Perl 6

while (my ($k, $v) = each(%hash)) { ... } # Perl 5
for %hash.kv -> $k, $v { ... } # Perl 6

Flow Control statements



There is no longer a continue block. Instead, use a NEXT block within the body of the loop.

# Perl 5
    my $str = '';
    for (1..5) {
        next if $_ % 2 == 1;
        $str .= $_;
    continue {
        $str .= ':'
# Perl 6
    my $str = '';
    for 1..5 {
        next if $_ % 2 == 1;
        $str ~= $_;
        NEXT {
            $str ~= ':'


Built-ins with bare blocks

Builtins that previously accepted a bare block followed, without a comma, by the remainder of the arguments will now require a comma between the block and the arguments e.g. map, grep, etc.

my @results = grep { $_ eq "bars" } @foo; # Perl 5
my @results = grep { $_ eq "bars" }, @foo; # Perl 6


Turned into an adverb of the {} hash subscripting and [] array subscripting operators.

my $deleted_value = delete $hash{$key};  # Perl 5
my $deleted_value = %hash{$key}:delete;  # Perl 6 - use :delete adverb

my $deleted_value = delete $array[$i];  # Perl 5
my $deleted_value = @array[$i]:delete;  # Perl 6 - use :delete adverb


Turned into an adverb of the {} hash subscripting and [] array subscripting operators.

say "element exists" if exists $hash{$key};  # Perl 5
say "element exists" if %hash{$key}:exists;  # Perl 6 - use :exists adverb

say "element exists" if exists $array[$i];  # Perl 5
say "element exists" if @array[$i]:exists;  # Perl 6 - use :exists adverb

Regular Expressions ( Regex / Regexp )

Change =~ and !~ to ~~ and !~~ .

In Perl 5, matches and substitutions are done against a variable using the =~ regexp-binding op.

In Perl 6, the ~~ smartmatch op is used instead.

next if $line  =~ /static/  ; # Perl 5
next if $line  ~~ /static/  ; # Perl 6

next if $line  !~ /dynamic/ ; # Perl 5
next if $line !~~ /dynamic/ ; # Perl 6

$line =~ s/abc/123/;          # Perl 5
$line ~~ s/abc/123/;          # Perl 6

Alternately, the new .match and .subst methods can be used. Note that .subst is non-mutating. See S05/Substitution.

Captures start with 0, not 1

/(.+)/ and print $1; # Perl 5
/(.+)/ and print $0; # Perl 6

Move modifiers

Move any modifiers from the end of the regex to the beginning. This may require you to add the optional m on a plain match like /abc/.

next if $line =~    /static/i ; # Perl 5
next if $line ~~ m:i/static/  ; # Perl 6

Add :P5 or :Perl5 adverb

If the actual regex is complex, you may want to use it as-is, by adding the P5 modifier.

next if $line =~    m/[aeiou]/   ; # Perl 5
next if $line ~~ m:P5/[aeiou]/   ; # Perl 6, using P5 modifier
next if $line ~~ m/  <[aeiou]> / ; # Perl 6, native new syntax

Special matchers generally fall under the <> syntax

There are many cases of special matching syntax that Perl 5 regexes support. They won't all be listed here, but often instead of being surrounded by (), the assertions will be surrounded by <>.

For character classes, this means that:

For look-around assertions:

(Unrelated to <> syntax, the "lookaround" /foo\Kbar/ becomes /foo <( bar )> /

Longest token matching (LTM) displaces alternation

In Perl 6 regexes, | does LTM, which decides which alternation wins an ambiguous match based off of a set of rules, rather than about which was written first.

The simplest way to deal with this is just to change any | in your Perl 5 regex to a ||.

TODO more rules. Use translate_regex.pl from Blue Tiger in the meantime.



Strict mode is now on by default.


Warnings are now on by default.

no warnings is currently NYI, but putting things in a quietly {} block will silence.


The functions which were altered by autodie to throw exceptions on error, now throw exceptions by default unless you test the return value explicitly.

# Perl 5
open my $i_fh, '<', $input_path;  # Fails silently on error
use autodie;
open my $o_fh, '>', $output_path; # Throws exception on error

# Perl 6
my $i_fh = open $input_path,  :r; # Throws exception on error
my $o_fh = open $output_path, :w; # Throws exception on error



Both use base and use parent have been replaced in Perl 6 by the is keyword, in the class declaration.

# Perl 5
package Cat;
use base qw(Animal);

# Perl 6
class Cat is Animal;

bigint bignum bigrat

No longer relevant.

Int is now arbitrary precision, as is the numerator of Rat (the denominator is limited to 2**64, after which it will automatically upgrade to Num to preserve performance). If you want a Rat with an arbitrary-precision denominator, FatRat is available.


In Perl 6, constant is a declarator for variables, just like my, except the variable is permanently locked to the result of its initialization expression (evaluated at compile time).

So, change the => to =.

use constant DEBUG => 0; # Perl 5
constant DEBUG = 0;      # Perl 6

use constant pi => 4 * atan2(1, 1); # Perl 5
# pi, e, i are built-in constants in  Perl 6


TODO Allows you to write your script in non-ascii or non-utf8


Perl pragma to use integer arithmetic instead of floating point


Manipulate @INC at compile time


No longer relevant.

In Perl 6, method calls now always use the C3 method resolution order.


No longer relevant.

In Perl 6, source code is expected to be in utf8 encoding.


Discouraged in Perl 5. See http://perldoc.perl.org/vars.html.

You should refactor your Perl 5 code to remove the need for use vars, before translating into Perl 6.

Command-line flags

See S19/commandline


-c -e -h -I -n -p -S -T -v -V


Unchanged in the Spec, but not yet implemented in Rakudo.

For now, change your code to use .split manually.


Unchanged in the Spec, but not yet implemented in Rakudo.

For now, change your code to use .split manually.


This is now the default behavior.

-M -m

Only -M remains. And, as you can no longer use the "no Module" syntax, the use of - with -M to "no" a module is no longer available.


Since all features are already enabled, just use lowercase -e .

-d, -dt, -d:foo, -D, etc.

Replaced with the ++BUG metasyntactic option.


Switch parsing is now done by the parameter list of the MAIN subroutine.

# Perl 5
    #!/usr/bin/perl -s
    if ($xyz) { print "$xyz\n" }
./example.pl -xyz=5

# Perl 6
    sub MAIN( Int :$xyz ) {
        say $xyz if $xyz.defined;
perl6 example.p6 --xyz=5
perl6 example.p6 -xyz=5

Taint warnings are not yet specified.

Removed. See S19#Removed Syntactic Features.

This is now the default behavior.

File-related operations

Reading the lines of a text file into an array

In Perl 5, a common idiom for reading the lines of a text file goes something like this:

open my $fh, "<", "file" or die "$!";
my @lines = <$fh>;
close $fh;

In Perl 6, this has been simplified to

my @lines = "file".IO.lines;

Do not be tempted to try slurping in a file and splitting the resulting string on newlines as this will give an array with a trailing empty element, which is one more than you probably expect (it's also more complicated), e.g.:

# initialize the file to read
spurt "test-file", q:to/END/;
first line
second line
third line
# read the file
my @lines = "test-file".IO.slurp.split(/\n/);
say @lines.elems;    #-> 4

Trapping the standard output of executables.

Whereas in Perl 5 you would do:

my $arg = 'Hello';
my $captured = `echo \Q$arg\E`;
my $captured = qx(echo \Q$arg\E);

Or using String::ShellQuote (because \Q…\E is not completely right):

my $arg = shell_quote 'Hello';
my $captured = `echo $arg`;
my $captured = qx(echo $arg);

In Perl 6, you will probably want to run commands without using the shell:

my $arg = 'Hello';
my $captured = run('echo', $arg, :out).out.slurp-rest;
my $captured = runecho "$arg"», :out).out.slurp-rest;

You can also use the shell if you really want to:

my $arg = 'Hello';
my $captured = shell("echo $arg", :out).out.slurp-rest;
my $captured = qqx{echo $arg};

But beware that in this case there is no protection at all! run does not use the shell, so there is no need to escape the arguments (arguments are passed directly). If you are using shell or qqx, then everything ends up being one long string which is then passed to the shell. Unless you validate your arguments very carefully, there is a high chance to introduce shell injection vulnerabilities with such code.

Environment variables

Perl module library path

In Perl5 one of the environment variables to specify extra search paths for Perl modules is PERL5LIB.

$ PERL5LIB="/some/module/lib" perl program.pl

In Perl 6 this is similar, one merely needs to change a number! As you probably guessed, you just need to use PERL6LIB:

$ PERL6LIB="/some/module/lib" perl6 program.p6

In Perl 5 one uses the ':' (colon) as a directory separator for PERL5LIB, but in Perl 6 one uses the ',' (comma). For example:

$ export PERL5LIB=/module/dir1:/module/dir2;


$ export PERL6LIB=/module/dir1,/module/dir2;

(Perl 6 does not recognize either the PERL5LIB or the older Perl environment variable PERLLIB.)

As with Perl5, if you don't specify PERL6LIB, you need to specify the library path within the program via the use lib pragma:

use lib '/some/module/lib'

Note that PERL6LIB is more of a developer convenience in Perl 6 (as opposed to the equivalent usage of PERL5LIB in Perl5) and shouldn't be used by module consumers as it could be removed in the future. This is because Perl 6's module loading isn't directly compatible with operating system paths.


'0' is True

Unlike Perl 5, a string containing nothing but zero ('0') is True. As Perl 6 has types in core, that makes more sense. This also means the common pattern:

... if defined $x and length $x; # or just length() in modern perls

In Perl 6 becomes a simple

... if $x;



The Perl 6 design allows for automatic transparent saving-and-loading of compiled bytecode.

Rakudo supports this only for modules so far.

Importing specific functions from a module

In Perl 5 it is possible to selectively import functions from a given module like so:

use ModuleName qw{foo bar baz};

In Perl 6 one specifies the functions which are to be exported by using the is export role on the relevant subs and all subs with this role are then exported. Hence, the following module Bar exports the subs foo and bar but not baz:

unit module Bar;

sub foo($a) is export { say "foo $a" }
sub bar($b) is export { say "bar $b" }
sub baz($z) { say "baz $z" }

To use this module, simply use Bar and the functions foo and bar will be available

use Bar;
foo(1);    #=> "foo 1"
bar(2);    #=> "bar 2"

If one tries to use baz an "Undeclared routine" error is raised at compile time.

So, how does one recreate the Perl 5 behaviour of being able to selectively import functions? For this one needs to define an EXPORT sub inside the module which specifies the functions to be exported and (in the current implementation of Rakudo (2015.03)) remove the module Bar statement. (Please note that not having the module statement isn't consistent with Synopsis 11, however it works.)

The module Bar now is merely a file called Bar.pm with the following contents:

use v6;

sub EXPORT(*@import-list) {
    my %exportable-subs =
        '&foo' => &foo,
        '&bar' => &bar,
    my %subs-to-export;
    for @import-list -> $import {
        if grep $sub-name, %exportable-subs.keys {
            %subs-to-export{$sub-name} = %exportable-subs{$sub-name};
    return %subs-to-export;

sub foo($a, $b, $c) { say "foo, $a, $b, $c" }
sub bar($a) { say "bar, $a" }
sub baz($z) { say "baz, $z" }

Note that the subs are no longer explicitly exported via the is export role. We are defining an EXPORT sub which specifies the subs in the module we want to be available for export and then we are populating a hash containing the subs which will actually be exported. The @import-list is set by the use statement in the calling code thus allowing us to selectively import the subs made available by the module.

So, to import only the foo routine, we do the following in the calling code:

use Bar <foo>;
foo(1);       #=> "foo 1"

Here we see that even though bar is able to be exported, if we don't explicitly import it, it's not available for use. Hence this causes an "Undeclared routine" error at compile time:

use Bar <foo>;
bar(5);       #!> "Undeclared routine: bar used at line 3"

however, this will work

use Bar <foo bar>;
foo(1);       #=> "foo 1"
bar(5);       #=> "bar 5"

Note also that baz remains unimportable even if specified in the use statement:

use Bar <foo bar baz>;
baz(3);       #!> "Undeclared routine: baz used at line 2"

In order to get this to work, one obviously has to jump through many hoops. In the standard use-case where one specifies the functions to be exported via the is export role, Perl 6 automatically creates the EXPORT sub in the correct manner for you, so one should consider very carefully whether or not writing one's own EXPORT routine is worthwhile.

Core modules


In Perl 5, the Data::Dumper module was used for serialization, and for debugging views of program data structures by the programmer.

In Perl 6, these tasks are accomplished with the .perl method, which every object has.

# Given:
    my @array_of_hashes = (
        { NAME => 'apple',   type => 'fruit' },
        { NAME => 'cabbage', type => 'no, please no' },
# Perl 5
    use Data::Dumper;
    $Data::Dumper::Useqq = 1;
    print Dumper \@array_of_hashes; # Note the backslash.
# Perl 6
    say @array_of_hashes.perl; # .perl on the array, not on its reference.

In Perl 5, Data::Dumper has a more complex optional calling convention, which allows for naming the VARs.

In Perl 6, placing a colon in front of the variable's sigil turns it into a Pair, with a key of the var name, and a value of the var value.

# Given:
    my ( $foo, $bar ) = ( 42, 44 );
    my @baz = ( 16, 32, 64, 'Hike!' );
# Perl 5
    use Data::Dumper;
    print Data::Dumper->Dump(
        [     $foo, $bar, \@baz   ],
        [ qw(  foo   bar   *baz ) ],
# Output
    $foo = 42;
    $bar = 44;
    @baz = (
# Perl 6
    say [ :$foo, :$bar, :@baz ].perl;
# Output
    ["foo" => 42, "bar" => 44, "baz" => [16, 32, 64, "Hike!"]]


Switch parsing is now done by the parameter list of the MAIN subroutine.

# Perl 5
    use 5.010;
    use Getopt::Long;
        'length=i' => \( my $length = 24       ), # numeric
        'file=s'   => \( my $data = 'file.dat' ), # string
        'verbose'  => \( my $verbose           ), # flag
    ) or die;
    say $length;
    say $data;
    say 'Verbosity ', ($verbose ? 'on' : 'off') if defined $verbose;
perl example.pl
perl example.pl --file=foo --length=42 --verbose
    Verbosity on

perl example.pl --length=abc
    Value "abc" invalid for option length (number expected)
    Died at c.pl line 3.

# Perl 6
    sub MAIN( Int :$length = 24, :file($data) = 'file.dat', Bool :$verbose ) {
        say $length if $length.defined;
        say $data   if $data.defined;
        say 'Verbosity ', ($verbose ?? 'on' !! 'off');
perl6 example.p6
    Verbosity off
perl6 example.p6 --file=foo --length=42 --verbose
    Verbosity on
perl6 example.p6 --length=abc
      c.p6 [--length=<Int>] [--file=<Any>] [--verbose]

Note that Perl 6 auto-generates a full usage message on error in command-line parsing.

Automated Translation

A quick way to find the Perl 6 version of a Perl 5 construct, is to run it through an automated translator.

NOTE: None of these translators are yet complete.

Blue Tiger

This project is dedicated to automated modernization of Perl code. It does not (yet) have a web front-end, and so must be locally installed to be useful. It also contains a separate program to translate Perl 5 regexes into Perl 6.



Online Translator!

This project is a suite of Perl cross-compilers, including Perl 5-to-6 translation. It has a web front-end, and so can be used without installation. It only supports a subset of Perl 5 syntax so far.



Larry Wall's own code for translating Perl 5 to Perl 6 has bit-rotted, and is not (currently) viable on recent releases of Perl 5.

MAD (Misc Attribute Definition) is a configuration option when building Perl from a source distribution. The `perl` executable analyses and translates your Perl sourcecode into an op-tree, and then executes the program by walking the op-tree. Normally, most of the details from the analysis are thrown away during this process. When MAD is enabled, the `perl` executable will save those details to an XML file, which can then be read and further processed into Perl 6 code by a MAD parser.

Please consult #perl6 to find out the best release of Perl 5 to use for your MAD science experiments.


Jeff Goff's Perl::ToPerl6 module for Perl 5 is designed around Perl::Critic's framework. It aims to convert Perl5 to compilable (if not necessarily running) Perl 6 code with the bare minimum of changes. Code transformers are configurable and pluggable, so you can create and contribute your own transformers, and customize existing transformers to your own needs. You can install the latest release from CPAN, or follow the project live on GitHub. An online converter may become available at some point.

Other sources of translation knowledge