Perl to Raku guide - in a nutshell
This page attempts to provide a fast-path to the changes in syntax and semantics from Perl to Raku. Whatever worked in Perl and must be written differently in Raku, should be listed here (whereas many new Raku features and idioms need not).
Hence this should not be mistaken for a beginner tutorial or a promotional overview of Raku; it is intended as a technical reference for Raku learners with a strong Perl background and for anyone porting Perl code to Raku (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 Raku." We don't mean to imply that Perl is now suddenly obsolete. Quite the contrary, most of us love Perl, and we expect Perl to continue in use for a good many years. Indeed, one of our more important goals has been to make interaction between Perl and Raku run smoothly. However, we do also like the design decisions in Raku, which are certainly newer and arguably better integrated than many of the historical design decisions in Perl. So many of us do hope that over the next decade or two, Raku 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.
Please note that some historic documents may refer to Raku by its original name, Perl 6, or to Perl as specifically Perl 5.
CPAN
See https://raku.land/.
If the module that you were using has not been converted to Raku, and no alternative is listed in this document, then its use under Raku may not have been addressed yet.
The Inline::Perl5 project makes
it possible to use
Perl modules directly from Raku code by using
an embedded instance of the perl
interpreter to run Perl code.
This is as simple as:
# the :from<Perl5> makes Raku load Inline::Perl5 first (if installed)
# and then load the Scalar::Util module from Perl
use Scalar::Util:from<Perl5> <looks_like_number>;
say looks_like_number "foo"; # OUTPUT: «0»
say looks_like_number "42"; # OUTPUT: «1»
A number of Perl modules have been ported to Raku, trying to maintain the API of these modules as much as possible, as part of the CPAN Butterfly Plan. These can be found at https://raku.land/?q=CPAN5.
Many Perl built-in functions (about a 100 so far) have been ported to
Raku with the same semantics. Think about the shift
function in Perl
having magic shifting from @_
or @ARGV
by default, depending on context.
These can be found at https://raku.land/zef:lizmat/P5built-ins and
its dependencies.
Syntax
There are a few differences in syntax between the two languages, starting with how identifiers are defined.
Identifiers
Raku allows the use of dashes (-
), underscores (_
),
apostrophes ('
), and alphanumerics in identifiers:
sub test-doesn't-hang { ... }
my $ความสงบ = 42;
my \Δ = 72; say 72 - Δ;
->
Method calls
If you've read any Raku code at all, it's immediately obvious that method call syntax now uses a dot instead of an arrow:
$person->name # Perl
$person.name # Raku
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
$object."$methodname"(@args); # Raku
If you leave out the quotes, then Raku expects $methodname
to contain
a Method object rather than the simple string name of the method. Yes,
everything in Raku can be considered an object.
Whitespace
Perl allows a surprising amount of flexibility in the use of whitespace, even with strict mode and warnings turned on:
# unidiomatic but valid Perl
say"Hello ".ucfirst ($people
[$ i]
->
name)."!"if$greeted[$i]<1;
Raku 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; Raku 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, but is either mandatory or forbidden in Raku. 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:
No space allowed before the opening parenthesis of an argument list.
substr ($s, 4, 1); # Perl (in Raku this would try to pass a single # argument of type List to substr)
substr($s, 4, 1); # Raku substr $s, 4, 1; # Raku - alternative parentheses-less style
Should this really be a problem for you, then you might want to have a look at the Slang::Tuxic module in the Raku ecosystem: it changes the grammar of Raku in such a way that you can have a space before the opening parenthesis of an argument list.
Space is required immediately after keywords
my($alpha, $beta); # Perl, tries to call my() sub in Raku
my ($alpha, $beta); # Raku
if($a < 0) { ... } # Perl, dies in Raku
if ($a < 0) { ... } # Raku if $a < 0 { ... } # Raku, more idiomatic
while($x-- > 5) { ... } # Perl, dies in Raku
while ($x-- > 5) { ... } # Raku while $x-- > 5 { ... } # Raku, more idiomatic
No space allowed after a prefix operator, or before a postfix/postcircumfix operator (including array/hash subscripts).
$seen {$_} ++; # Perl
%seen{$_}++; # Raku
Space required before an infix operator if it would conflict with an existing postfix/postcircumfix operator.
$n<1; # Perl (in Raku this would conflict with postcircumfix < >)
$n < 1; # Raku
However, whitespace is allowed before the period of a method call!
# Perl my @books = $xml ->parse_file($file) # some comment ->findnodes("/library/book");
# Raku my @books = $xml .parse-file($file) # some comment .findnodes("/library/book");
However, note that you can use unspace to add whitespace in Raku code in places where it is otherwise not allowed.
See also other lexical conventions in the syntax page.
Sigils
In Perl, arrays and hashes use changing sigils depending on how they are being accessed. In Raku the sigils are invariant, no matter how the variable is being used - you can think of them as part of the variable's name.
$
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
my $sub = &foo; # Raku
callback => sub { say @_ } # Perl - can't pass built-in sub directly
callback => &say # Raku - & gives "noun" form of any sub
Since Raku does not allow adding/removing symbols in a lexical scope once
it has finished compiling, there is no equivalent to Perl's
undef &foo;
, and the closest equivalent to Perl'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, the ampersand sigil can additionally be used to call subroutines in special ways with subtly different behavior compared to normal sub calls. In Raku those special forms are no longer available:
&foo(...)
for circumventing a function prototypeIn Raku there are no prototypes, and it no longer makes a difference whether you, say, pass a literal code block or a variable holding a code object as an argument:
# Perl: first_index { $_ > 5 } @values; &first_index($coderef, @values); # (disabling the prototype that parses a # literal block as the first argument)
# Raku: first { $_ > 5 }, @values, :k; # the :k makes first return an index first $coderef, @values, :k;
&foo;
andgoto &foo;
for re-using the caller's argument list / replacing the caller in the call stack. Raku can use either callsame for re-dispatching or nextsame and nextwith, which have no exact equivalent in Perl.sub foo { say "before"; &bar; say "after" } # Perl
sub foo { say "before"; bar(|@_); say "after" } # Raku - have to be explicit
sub foo { say "before"; goto &bar } # Perl
proto foo (|) {*}; multi foo ( Any $n ) { say "Any"; say $n; }; multi foo ( Int $n ) { say "Int"; callsame; }; foo(3); # /language/functions#sub_callsame
*
Glob
In Perl, the *
sigil referred to the GLOB structure that Perl uses to
store non-lexical variables, filehandles, subs, and formats.
You are most likely to encounter a GLOB in code written on an early Perl version that does not support lexical filehandles, when a filehandle needed to be passed into a sub.
# Perl - 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 code to remove the need for the GLOB, before translating into Raku.
# Perl - 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 Raku translation:
# Raku
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:
Indexing
say $months[2]; # Perl
say @months[2]; # Raku - @ instead of $
Value-slicing
say join ',', @months[6, 8..11]; # Perl and Raku
Key/value-slicing
say join ',', %months[6, 8..11]; # Perl
say join ',', @months[6, 8..11]:kv; # Raku - @ instead of %; use :kv adverb
Also note that the subscripting square 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.
An array's biggest index is now available with the .end
method:
say $#item; # Perl
say @item.end; # Raku
{} 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):
Indexing
say $calories{"apple"}; # Perl
say %calories{"apple"}; # Raku - % instead of $
say $calories{apple}; # Perl
say %calories<apple>; # Raku - angle brackets; % instead of $ say %calories«"$key"»; # Raku - double angles interpolate as a list of Str
Value-slicing
say join ',', @calories{'pear', 'plum'}; # Perl
say join ',', %calories{'pear', 'plum'}; # Raku - % instead of @ say join ',', %calories<pear plum>; # Raku (prettier version) my $keys = 'pear plum'; say join ',', %calories«$keys»; # Raku the split is done after interpolation
Key/value-slicing
say join ',', %calories{'pear', 'plum'}; # Perl
say join ',', %calories{'pear', 'plum'}:kv; # Raku - use :kv adverb say join ',', %calories<pear plum>:kv; # Raku (prettier version)
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.
Creating references and using them
In Perl, 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. the "referencing/dereferencing"
metaphor does not map cleanly to the actual Raku container system,
so we will have to focus on the intent of the reference operators
instead of the actual syntax.
my $aref = \@aaa ; # Perl
This might be used for passing a reference to a routine, for instance. But in Raku, the (single) underlying object is passed (which you could consider to be a sort of pass by reference).
my @array = 4,8,15;
{ $_[0] = 66 }(@array); # run the block with @array aliased to $_
say @array; # OUTPUT: «[66 8 15]»
The underlying Array object of @array
is passed, and its first value
modified inside the declared routine.
In Perl, the syntax for dereferencing an entire reference is the type-sigil and curly braces, with the reference inside the curly braces. In Raku, this concept simply does not apply, since the reference metaphor does not really apply.
In Perl, the arrow operator, ->
, is used for single access to a
composite's reference or to call a sub through its reference. In Raku, the dot
operator .
is always used for object methods, but the rest does not really
apply.
# Perl
say $arrayref->[7];
say $hashref->{'fire bad'};
say $subref->($foo, $bar);
In relatively recent versions of Perl (5.20 and later), a new feature allows
the use of the arrow operator for dereferencing: see Postfix Dereferencing.
This can be used to create an array from a scalar. This operation is usually
called decont, as in decontainerization, and in Raku methods such as
.list
and .hash
are used:
# Perl 5.20
use experimental qw< postderef >;
my @a = $arrayref->@*;
my %h = $hashref->%*;
my @slice = $arrayref->@[3..7];
# Raku
my @a = $contains-an-array.list; # or @($arrayref)
my %h = $contains-a-hash.hash; # or %($hashref)
The "Zen" slice does the same thing:
# Raku
my @a = $contains-an-array[];
my %h = $contains-a-hash{};
See the "Containers" section of the documentation for more information.
Operators
See the documentation for operators for full details on all operators.
Unchanged:
+
Numeric Addition-
Numeric Subtraction*
Numeric Multiplication/
Numeric Division%
Numeric Modulus**
Numeric Exponentiation++
Numeric Increment--
Numeric Decrement! && || ^
Booleans, high-precedencenot and or xor
Booleans, low-precedence== != < > <= >=
Numeric comparisonseq ne lt gt le ge
String comparisons
,
(Comma) List separator
Unchanged, but note that in order to flatten an array variable to a list (in
order to append or prefix more items) one should use the |
operator
(see also Slip). For instance:
my @numbers = 100, 200, 300;
my @more_numbers = 500, 600, 700;
my @all_numbers = |@numbers, 400, |@more_numbers;
That way one can concatenate arrays.
Note that one does not need to have any parentheses on the right-hand side: the list separator takes care of creating the list, not the parentheses!
<=> cmp
Three-way comparisons
In Perl, these operators returned -1, 0, or 1.
In Raku, 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 Raku does either <=>
or leg
, depending on the existing
type of its arguments.
~~
Smartmatch operator
While the operator has not changed, the rules for what exactly is matched depend on the types of both arguments, and those rules are far from identical in Perl and Raku. See ~~ and the smartmatch operator
& | ^
String bitwise ops
& | ^
Numeric bitwise ops
& | ^
Boolean ops
In Perl, & | ^
were invoked according to the contents of their
arguments. For example, 31 | 33
returns a different result than "31" |
"33"
.
In Raku, 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
say 42 +< 3; # Raku
=>
Fat comma
In Perl, =>
acted just like a comma, but also quoted its left-hand
side.
In Raku, =>
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.
sub get_the_loot { ... }; # Raku stub
# Works in Perl and Raku
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 that fat arrow 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
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 );
# Raku, 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
# Raku, API changed to specify valid options
# The colon before the sigils means to expect a named variable,
# 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
The conditional operator ? :
has been replaced
by ?? !!
:
my $result = $score > 60 ? 'Pass' : 'Fail'; # Perl
my $result = $score > 60 ?? 'Pass' !! 'Fail'; # Raku
.
(Dot) String concatenation
Replaced by the tilde.
Mnemonic: think of "stitching" together the two strings with needle and thread.
$food = 'grape' . 'fruit'; # Perl
$food = 'grape' ~ 'fruit'; # Raku
x
List repetition or string repetition operator
In Perl, x
is the repetition operator, which behaves differently in
scalar or list contexts:
in scalar context
x
repeats a string;in list context
x
repeats a list, but only if the left argument is parenthesized!
Raku uses two different repetition operators to achieve the above:
x
for string repetitions (in any context);xx
for list repetitions (in any context).
Mnemonic: x
is short and xx
is long, so xx
is the one used for lists.
# Perl
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
# Raku
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, ..
was one of two completely different operators, depending
on context.
In list context, ..
is the familiar range operator. Ranges from Perl
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, "${foo}s"
deliminates a variable name from regular text next to
it. In Raku, simply extend the curly braces to include the sigil too:
"{$foo}s"
. This is in fact a very simple case of interpolating an expression.
Compound statements
These statements include conditionals and loops.
Conditionals
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
if dostuff() -> $x {...} # Raku
(You can still use the my
form in Raku, but it will scope to the
outer block, not the inner.)
The unless
conditional only allows for a single block in Raku;
it does not allow for an elsif
or else
clause.
given
-when
The given
-when
construct is like a chain of if
-elsif
-else
statements or like the switch
-case
construct C, for example. It has the
general structure:
given EXPR {
when EXPR { ... }
when EXPR { ... }
default { ... }
}
In its simplest form, the construct is as follows:
given $value { # assigns $_
when "a match" { # if $_ ~~ "a match"
# do-something();
}
when "another match" { # elsif $_ ~~ "another match"
# do-something-else();
}
default { # else
# do-default-thing();
}
}
This is simple in the sense that a scalar value is matched in the when
statements against $_
, which was set by the given
. More generally,
the matches are actually smartmatches on $_
such that lookups using more
complex entities such as regexps can be used instead of scalar values.
See also the warnings on the smartmatch op above.
Loops
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
while dostuff() -> $x {...} # Raku
(You can still use the my
form in Raku, but it will scope to the
outer block, not the inner.)
Note that reading line-by-line from a filehandle has changed.
In Perl, 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 Raku, for
statement is lazy, so we read line-by-line in a for
loop using the .lines
method.
while (<IN_FH>) { } # Perl
for $IN_FH.lines { } # Raku
Also note that in Raku, lines are chomp
ed by default.
do
while
/until
# Perl
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:
# Raku
repeat {
...
} while $x < 10;
repeat {
...
} until $x >= 10;
Note that Perl's unadorned do
block ('do {...}
') behaves the same
when used in Raku.
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 compiler looks for the
semicolons 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
loop ( my $i = 1; $i <= 10; $i++ ) { ... } # Raku
The loop-iterator form is named for
in Raku and foreach
is no longer a keyword.
The for
loop has the following rules:
parentheses are optional;
the iteration variable, if any, has been moved from appearing before the list, to appearing after the list and an added arrow operator;
the iteration variable is now always lexical:
my
is neither needed nor allowed;the iteration variable is a read-only alias to the current list element (in Perl it is a read-write alias!). If a read-write alias is required, change the
->
before the iteration variable to a<->
. When translating from Perl, inspect the use of the loop variable to decide if read-write is needed.
for my $car (@cars) {...} # Perl; read-write
for @cars -> $car {...} # Raku; read-only
for @cars <-> $car {...} # Raku; read-write
In Raku and unlike Perl, the default topic $_
will behave in the same way,
becoming read-only when used as a topic variable.
for (@cars) {...} # Perl; $_ is read-write
for @cars {...} # Raku; $_ is read-only
for @cars <-> $_ {...} # Raku; $_ is also read-write
It is possible to consume more than one element of the list in each iteration simply specifying more than one variable after the arrow operator:
my @array = 1..10;
for @array -> $first, $second {
say "First is $first, second is $second";
}
For cases in which the number of elements iterated over isn't a multiple of the number of variables after the arrow operator, you can provide variables with default values:
my @array = 1..9;
for @array -> $first, $second = 0 {
say "First is $first, second is $second";
}
each
Here is the equivalent to Perl’s while…each(%hash)
or while…each(@array)
(i.e., iterating over both the keys/indices and values of a data structure) in
Raku:
while (my ($i, $v) = each(@array)) { ... } # Perl
for @array.kv -> $i, $v { ... } # Raku
while (my ($k, $v) = each(%hash)) { ... } # Perl
for %hash.kv -> $k, $v { ... } # Raku
Flow control statements
Unchanged:
next
last
redo
continue
There is no longer a continue
block.
Instead, use a NEXT
block (phaser) within the body of the loop.
# Perl
my $str = '';
for (1..5) {
next if $_ % 2 == 1;
$str .= $_;
}
continue {
$str .= ':'
}
# Raku
my $str = '';
for 1..5 {
next if $_ % 2 == 1;
$str ~= $_;
NEXT {
$str ~= ':'
}
}
Please note that phasers don't really need a block. This can be very handy when you don't want another scope:
# Raku
my $str = '';
for 1..5 {
next if $_ % 2 == 1;
$str ~= $_;
NEXT $str ~= ':';
}
Functions
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
my @results = grep { $_ eq "bars" }, @foo; # Raku
delete
Turned into an adverb of the {} hash subscripting and [] array subscripting operators.
my $deleted_value = delete $hash{$key}; # Perl
my $deleted_value = %hash{$key}:delete; # Raku - use :delete adverb
my $deleted_value = delete $array[$i]; # Perl
my $deleted_value = @array[$i]:delete; # Raku - use :delete adverb
exists
Turned into an adverb of the {} hash subscripting and [] array subscripting operators.
say "element exists" if exists $hash{$key}; # Perl
say "element exists" if %hash{$key}:exists; # Raku - use :exists adverb
say "element exists" if exists $array[$i]; # Perl
say "element exists" if @array[$i]:exists; # Raku - use :exists adverb
Regular expressions ( regex / regexp )
Change =~
and !~
to ~~
and !~~
.
In Perl, matches and substitutions are done against a variable using the
=~
regexp-binding op.
In Raku, the ~~
smartmatch op is used instead.
next if $line =~ /static/ ; # Perl
next if $line ~~ /static/ ; # Raku
next if $line !~ /dynamic/ ; # Perl
next if $line !~~ /dynamic/ ; # Raku
$line =~ s/abc/123/; # Perl
$line ~~ s/abc/123/; # Raku
Alternately, the new .match
and .subst
methods can be used. Note that
.subst is non-mutating.
Captures start with 0, not 1
/(.+)/ and print $1; # Perl
/(.+)/ and print $0; # Raku
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
next if $line ~~ m:i/static/ ; # Raku
Add :P5 or :Perl5 adverb
If the actual regex is complex, you may want to use it as-is (with some exceptions),
by adding the P5
modifier.
next if $line =~ m/[aeiou]/ ; # Perl
next if $line ~~ m:P5/[aeiou]/ ; # Raku, using P5 modifier
next if $line ~~ m/ <[aeiou]> / ; # Raku, native new syntax
If the Perl regex has any modifiers, move them from the end and place them
after the P5
modifier. Each modifier will have to be separated from any
others by a colon. For example:
my $a = "abcabc";
my $b = $a;
$a =~ s/abcaBc//gi; # Perl 5
$a ~~ s:P5:g:i/ab//; # Raku, using P5 modifier
$b ~~ s:gi/ab//; # Raku, native new syntax
say $a;
say $b;
Another accommodation required with the P5 syntax is to replace curly braces with square brackets when specifying Unicode in the expression:
next if $line =~ m/\x{2043};
next if $line ~~ m:P5/\x[2043]/;
next if $line ~~ /\x[2043]/;
Please note that the Perl regular expression syntax dates from many years
ago and may lack features that have been added since the beginning of the
Raku project. Two such features not implemented in Raku for the P5
syntax are the Perl Unicode property matchers \p{}
and \P{}
.
Special matchers generally fall under the <>
syntax
There are many cases of special matching syntax that Perl 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:
[abc]
becomes<[abc]>
[^abc]
becomes<-[abc]>
[a-zA-Z]
becomes<[a..zA..Z]>
[[:upper:]]
becomes<:Upper>
[abc[:upper:]]
becomes<[abc]+:Upper>
For lookaround assertions:
(?=[abc])
becomes<?[abc]>
(?=ar?bitrary* pattern)
becomes<before ar?bitrary* pattern>
(?!=[abc])
becomes<![abc]>
(?!=ar?bitrary* pattern)
becomes<!before ar?bitrary* pattern>
(?<=ar?bitrary* pattern)
becomes<after ar?bitrary* pattern>
(?<!ar?bitrary* pattern)
becomes<!after ar?bitrary* pattern>
For more info see lookahead assertions.
(Unrelated to <>
syntax, the "lookaround" /foo\Kbar/
becomes /foo <( bar )> /
(?(?{condition))yes-pattern|no-pattern)
becomes[ <?{condition}> yes-pattern | no-pattern ]
Longest token matching (LTM) displaces alternation
In Raku 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 regex to a ||
.
However, if a regex written with ||
is inherited or composed into a grammar
that uses |
either by design or typo, the result may not work as expected.
So when the matching process becomes complex, you finally need to have some
understanding of both, especially how LTM strategy works. Besides, |
may be
a better choice for grammar reuse.
Named captures
These work in a slightly different way; also they only work in the latest versions of Perl.
use v5.22;
"þor is mighty" =~ /is (?<iswhat>\w+)/n;
say $+{iswhat};
The iswhat
within a non-capturing group is used to actually capture what is
behind, and up to the end of the group (the )
). The capture goes to the %+
hash under the key with the name of the capture. In Raku
named captures work this way
"þor is mighty" ~~ /is \s+ $<iswhat>=(\w+)/;
say $<iswhat>;
An actual assignment is made within the regular expression; that's the same syntax used for the variable outside it.
Comments
As with Perl, comments work as usual in regexes.
/ word #`(match lexical "word") /
BEGIN, UNITCHECK, CHECK, INIT and END
Except for UNITCHECK
, all of these special blocks exist in Raku as well.
In Raku, these are called Phasers. But there are some
differences!
UNITCHECK becomes CHECK
There is currently no direct equivalent of CHECK
blocks in Raku. The
CHECK
phaser in Raku has the same semantics as the UNITCHECK
block in
Perl: it gets run whenever the compilation unit in which it occurs has
finished parsing. This is considered a much saner semantic than the current
semantics of CHECK
blocks in Perl. But for compatibility reasons, it was
impossible to change the semantics of CHECK
blocks in Perl, so a
UNITCHECK
block was introduced in 5.10. Consequently, it was decided that
the Raku CHECK
phaser would follow the saner Perl UNITCHECK
semantics.
No block necessary
In Perl, these special blocks must have curly braces, which implies a separate scope. In Raku this is not necessary, allowing these special blocks to share their scope with the surrounding lexical scope.
my $foo; # Perl
BEGIN { $foo = 42 }
BEGIN my $foo = 42; # Raku
Changed semantics with regards to precompilation
If you put BEGIN
and CHECK
phasers in a module that is being precompiled,
then these phasers will only be executed during precompilation and not
when a precompiled module is being loaded. So when porting module code from
Perl, you may need to change BEGIN
and CHECK
blocks to INIT
blocks to
ensure that they're run when loading that module.
Pragmas
strict
Strict mode is now on by default.
warnings
Warnings are now on by default.
no warnings
can be achieved by wrapping code in a quietly
{} block.
autodie
The functions which were altered by autodie
to throw exceptions on
error, now generally return Failures by default. You can test a Failure
for definedness / truthiness without any problem. If you use the Failure
in any other way, then the Exception that was encapsulated by the Failure
will be thrown.
# Perl
open my $i_fh, '<', $input_path; # Fails silently on error
use autodie;
open my $o_fh, '>', $output_path; # Throws exception on error
# Raku
my $i_fh = open $input_path, :r; # Returns Failure on error
my $o_fh = open $output_path, :w; # Returns Failure on error
Because you can check for truthiness without any problem, you can use the
result of an open
in an if
statement:
# Raku
if open($input_path,:r) -> $handle {
.say for $handle.lines;
}
else {
# gracefully handle the fact that the open() failed
}
base
, parent
Both use base
and use parent
have been replaced in Raku by the
is
keyword, in the class declaration.
# Perl
package Cat;
use base qw(Animal);
# Raku
class Cat is Animal {}
Note that the Animal
class must be known at compilation time prior to
be able to inherit from it.
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.
constant
In Raku, 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
constant DEBUG = 0; # Raku
use constant pi => 4 * atan2(1, 1); # Perl
tau, pi, e, i; # built-in constants in Raku
τ, π, 𝑒 # and their unicode equivalents
encoding
Allows you to write your script in non-ascii or non-utf8. Raku uses, for the time being, only utf8 for its scripts.
use integer
Perl pragma to use integer arithmetic instead of floating point. There is no such thing in Raku. If you use native integers in your calculations, then this will be the closest thing.
#Raku
my int $foo = 42;
my int $bar = 666;
say $foo * $bar; # uses native integer multiplication
use lib
Manipulate where modules are looked up at compile time. The underlying logic is
very different from Perl, but in the case you are using an equivalent
syntax, use lib
in Raku works the same as in Perl.
use mro
No longer relevant.
In Raku, method calls now always use the C3 method resolution order.
If you need to find out parent classes of a given class, you can invoke the
mro
metamethod thusly:
say Animal.^mro; # .^ indicates calling a metamethod on the object
use utf8
No longer relevant: in Raku, source code is expected to be in utf8 encoding.
use vars
Discouraged in Perl. See https://perldoc.perl.org/vars.html.
You should refactor your Perl code to remove the need for use vars
,
before translating into Raku.
Command-line flags
See the command line flags that Rakudo uses
Unchanged:
-c -e -h -I -n -p -v -V
-a
Change your code to use .split
manually.
-F
Change your code to use .split
manually.
-l
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.
-E
Since all features are already enabled, just use lowercase -e
.
-d
, -dt
, -d:foo
, -D
, etc.
Replaced with the ++BUG
metasyntactic option.
-s
Switch parsing is now done by the parameter list of the MAIN
subroutine.
# Perl
#!/usr/bin/perl -s
if ($xyz) { print "$xyz\n" }
./example.pl -xyz=5
5
# Raku
sub MAIN( Int :$xyz ) {
say $xyz if $xyz.defined;
}
raku example.raku --xyz=5
5
raku example.raku -xyz=5
5
-t
Removed.
-P
-u
-U
-W
-X
Removed. See Removed Syntactic Features.
-w
This is now the default behavior.
-S
,-T
.
This has been eliminated. Several ways to replicate "taint" mode are discussed in Reddit.
File-related operations
Reading the lines of a text file into an array
In Perl, a common idiom for reading the lines of a text file goes something like this:
open my $fh, "<", "file" or die "$!";
my @lines = <$fh>; # lines are NOT chomped
close $fh;
In Raku, this has been simplified to
my @lines = "file".IO.lines; # auto-chomped
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
END
# read the file
my @lines = "test-file".IO.slurp.split(/\n/);
say @lines.elems; #-> 4
If for some reason you do want to slurp the file first, then you can call
the lines
method on the result of slurp
instead:
my @lines = "test-file".IO.slurp.lines; # also auto-chomps
Also, be aware that $!
is not really relevant for file IO operation failures
in Raku. An IO operation that fails will return a Failure instead of
throwing an exception. If you want to return the failure message, it is in the
failure itself, not in $!
. To do similar IO error checking and reporting as
in Perl:
my $fh = open('./bad/path/to/file', :w) or die $fh;
Note: $fh
instead of $!
. Or, you can set $_
to the failure and die
with $_:
my $fh = open('./bad/path/to/file', :w) orelse .die; # Raku
Any operation that tries to use the failure will cause the program to fault and
terminate. Even just a call to the .self
method is sufficient.
my $fh = open('./bad/path/to/file', :w).self;
Capturing the standard output of executables.
Whereas in Perl 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 Raku, you will probably want to run commands without using the shell:
my $arg = 'Hello';
my $captured = run('echo', $arg, :out).out.slurp;
my $captured = run(«echo "$arg"», :out).out.slurp;
You can also use the shell if you really want to:
my $arg = 'Hello';
my $captured = shell("echo $arg", :out).out.slurp;
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 of introducing
shell injection vulnerabilities with such code.
Environment variables
Perl module library path
Perl use PERLLIB
and PERL5LIB
to specify extra search paths for modules
and Both of them are ignored by Raku. Instead, you need to use RAKULIB
|Reference,RAKULIB.
The directory separator also changed from ':' to ','.
$ export PERL5LIB=/module/dir1:/module/dir2;
is
$ export RAKULIB=/module/dir1,/module/dir2;
As with Perl, if you don't specify RAKULIB
, you need to specify the
library path within the program via the use lib
pragma:
use lib '/some/module/lib'
Note that RAKULIB
is more of a developer convenience in Raku (as
opposed to the equivalent usage of PERL5LIB
in Perl) and shouldn't be
used by module consumers as it could be removed in the future. This is
because Raku's module loading isn't directly compatible with operating
system paths.
Misc.
'0'
is True
Unlike Perl, a string containing nothing but zero ('0') is True
. As Raku
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 Raku becomes a simple
... if $x;
dump
Gone.
The Raku design allows for automatic and transparent saving-and-loading of compiled bytecode.
Rakudo supports this only for modules so far.
AUTOLOAD
The FALLBACK method provides similar functionality.
Importing specific functions from a module
In Perl it is possible to selectively import functions from a given module like so:
use ModuleName qw{foo bar baz};
In Raku one specifies the functions which are to be exported by using
the is export
role on the relevant subs; 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 behavior of being able to
selectively import functions? By defining an EXPORT
sub inside the
module which specifies the functions to be exported and removing the
module Bar
statement.
The former module Bar
now is merely a file called Bar.rakumod
with the
following contents:
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, but by an EXPORT
sub which specifies the subs
in the module we want to make 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 exportable, 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>;
foo(1);
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, Raku 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.
Importing groups of specific functions from a module
If you would like to export groups of functions from a module, you just
need to assign names to the groups, and the rest will work
automagically. When you specify is export
in a sub declaration, you
are in fact adding this subroutine to the :DEFAULT
export group. But
you can add a subroutine to another group, or to multiple groups:
unit module Bar;
sub foo() is export { } # added by default to :DEFAULT
sub bar() is export(:FNORBL) { } # added to the FNORBL export group
sub baz() is export(:DEFAULT:FNORBL) { } # added to both
So now you can use the Bar
module like this:
use Bar; # imports foo / baz
use Bar :FNORBL; # imports bar / baz
use Bar :ALL; # imports foo / bar / baz
Note that :ALL
is an auto-generated group that encompasses all
subroutines that have an is export
trait.
Core modules
Data::Dumper
In Perl, the Data::Dumper module was used for serialization, and for debugging views of program data structures by the programmer.
In Raku, these tasks are accomplished with the .raku
method, which
every object has.
# Given:
my @array_of_hashes = (
{ NAME => 'apple', type => 'fruit' },
{ NAME => 'cabbage', type => 'no, please no' },
);
# Perl
use Data::Dumper;
$Data::Dumper::Useqq = 1;
print Dumper \@array_of_hashes; # Note the backslash.
# Raku
say @array_of_hashes.raku; # .raku on the array, not on its reference.
In Perl, Data::Dumper has a more complex optional calling convention, which allows for naming the VARs.
In Raku, 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
use Data::Dumper;
print Data::Dumper->Dump(
[ $foo, $bar, \@baz ],
[ qw( foo bar *baz ) ],
);
# Output
# $foo = 42;
# $bar = 44;
# @baz = (
# 16,
# 32,
# 64,
# 'Hike!'
# );
# Raku
say [ :$foo, :$bar, :@baz ].raku;
# OUTPUT: «["foo" => 42, "bar" => 44, "baz" => [16, 32, 64, "Hike!"]]»
There is also a Rakudo-specific debugging aid for developers called dd
(Tiny
Data Dumper, so tiny it lost the "t"). This will print the .raku
representation plus some extra information that could be introspected, of the
given variables on STDERR:
# Raku
dd $foo, $bar, @baz;
# OUTPUT: «Int $foo = 42Int $bar = 44Array @baz = [16, 32, 64, "Hike!"]»
Getopt::Long
Switch parsing is now done by the parameter list of the MAIN
subroutine.
# Perl
use 5.010;
use Getopt::Long;
GetOptions(
'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
24
file.dat
perl example.pl --file=foo --length=42 --verbose
42
foo
Verbosity on
perl example.pl --length=abc
Value "abc" invalid for option length (number expected)
Died at c.pl line 3.
# Raku
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');
}
raku example.raku
24
file.dat
Verbosity off
raku example.raku --file=foo --length=42 --verbose
42
foo
Verbosity on
raku example.raku --length=abc
Usage:
c.raku [--length=<Int>] [--file=<Any>] [--verbose]
Note that Raku auto-generates a full usage message on error in command-line parsing.
Automated translation
A quick way to find the Raku version of a Perl 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 regexes into Raku.
https://github.com/Util/Blue_Tiger/
Perlito
Online translator!
This project is a suite of Perl cross-compilers, including Perl to Raku translation. It has a web front-end, and so can be used without installation. It only supports a subset of Perl syntax so far.
https://fglock.github.io/Perlito/perlito/perlito5.html
Perl-ToPerl6
The late Jeff Goff's Perl::ToPerl6 module for Perl is designed around Perl::Critic's framework. It aims to convert Perl to compilable (if not necessarily running) Raku 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
[1]This should not be confused with the Perl built-in glob()
function,
which reads filenames from a directory.