Perl 6 from Ruby - Nutshell

Learning Perl 6 from Ruby, in a nutshell: What do I already know?

This page attempts to index the high-level differences in syntax and semantics between Ruby and Perl 6. Whatever works in Ruby and must be written differently in Perl 6 should be listed here (whereas many Perl 6 features and idioms won't be).

Hence this should not be mistaken for a beginner tutorial or overview of Perl 6; it is intended as a technical reference for Perl 6 learners with a strong Ruby background.

Basic Syntax

Statement Ending Semi-Colons

Ruby detects the end of most statements with a newline (and a few exceptions), as long as the expression is complete. It is common break up a long expression by leaving an operator dangling at the end of a line to ensure that the parsing will continue:

foo +     # In Ruby a trailing operator means parsing should continue 
  bar +

In Perl 6 you must explicitly terminate statements with a ;, which allows for better feedback and more flexibility in breaking up long lines. Two exceptions not needing an explicit ; are the last statement in a block, and after the closing curly brace of the block itself (if there is nothing else on that line):

if 5 < $x < 10 {
  say "Yep!";
  $x = 17         # No ; required before closing } 
}                 # No ; required after closing } because of the newline 
say "Done!";      # The ; is not required here if nothing follows 


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

# unidiomatic but valid Ruby 
puts"Hello "+
(people [ i]
    . name
    ) . upcase+"!"if$greeted[i]<1

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 Ruby, 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 an array variable and its square braces), but there are a few that will unfortunately conflict with some Ruby hackers' habitual coding styles:

. Method calls, .send

Method call syntax uses a dot just like Ruby:    # Ruby 
$   # Perl 6 

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

object.send(methodnameargs);  # Ruby 
$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.

Variables, Sigils, Scope, and Common Types

In Ruby, variables use sigils primarily to indicate scope. $ for global scope, @@ for class scope, @ for instance scope, and no sigil for local variables (including parameters). The & sigil is also used to indicate method references. Symbols are prefixed with :, but they are not variable and so not really sigils.

In Perl 6 sigils are primarily used to indicate a role that the contained value implements, indicating the type (or at least the interface) of the value. The sigils are invariant, no matter how the variable is being used - you can think of them as part of the variable's name.

The scope of a variable is instead indicated by the declaration itself (my, has, our, etc).

Variable Scope

For local variables, Ruby uses implicit variable declaration upon assignment and limited to the current block. In Ruby the content of an if or while built-in construct is not a block or scope.

Perl 6 uses explicit scope indicators, and never creates variables implicitly. Every place you see { ... } is a scope, including the body of a conditional or loop. The commonly used scope declarations:

foo = 7        # Ruby, variable scope is defined by first assignment and 
               # extends to the end of the current block 
my  $foo = 7   # Perl 6, lexical scoped to the current block 
our $foo = 7   # Perl 6, package scoped 
has $!foo = 7  # Perl 6, instance scoped (attribute) 

$ Scalar

The $ sigil is always used with "scalar" variables (e.g. $name). These are single-value containers.

This is the most general-purpose variable type, with no restrictions on its contents. Note that you can still address/use its contents, like $x[1], $x{"foo"}, and $f("foo").

@ Array

The @ sigil is always used with "array" variables (e.g. @months, @months[2], @months[2, 4] for an array slice). Variables using the @ sigil can only contain things that do the Positional role, indicating positional indexing and slicing capabilities.

% Hash

The % sigil is always used with "hash" variables (e.g. %calories, %calories<apple>, %calories<pear plum>). Variables using the % sigil can only contain things that do the Associative role.

Ruby uses square brackets to access values for both Arrays and Hashes. Perl 6 uses curly braces for hashes instead. The angle-brackets version is available which always autoquotes its contents (strings without quotes):

Adverbs can be used to control the type of slice.

& Sub

The & sigil is used very similarly to Ruby's & 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". Variables using the & sigil can only contain things that do the Callable role.

add = -> n, m { n + m } # Ruby lambda for an addition function 
add.(23)              # => 5, Ruby invocation of a lambda          # => 5, Ruby invocation of a lambda 
my &add = -> $n$m { $n + $m } # Perl 6 addition function 
&add(23)                      # => 5, you can keep the sigil 
add(23)                       # => 5, and it works without it 
foo_method = &foo;     # Ruby 
my &foo_method = &foo# Perl 6 
some_func(&say# Ruby pass a function reference 
some_func(&say# Perl 6 passes function references the same way 

Often in Ruby we pass a block as the last parameter, which is especially used for DSLs. This can be an implicit parameter called by yield, or an explicit block prefixed with &. In Perl 6 a Callable parameter is always listed and called by the variable name (instead of yield), and there are a variety of ways of invoking the function.

# Ruby, declare a method and call the implicit block argument 
def f
  yield 2
# Ruby, invoke f, pass it a block with 1 argument 
f do |n|
  puts "Hi #{n}"
# Perl 6, declare a method with an explicit block argument 
sub f(&g:($)) {
# Perl 6, invoke f, pass it a block with 1 argument 
# There are several other ways to do this 
f(-> $n { say "Hi {$n}" }# Explicit argument 
f -> $n { say "Hi {$n}" }  # Explicit argument, no parenthesis 
f { say "Hi {$^n}" }       # Implicit argument 
# Additionally, if 'f' is a method on instance 'obj' you can use C<:> 
# instead of parenthesis 
obj.f(-> $n { say "Hi {$n}" })  # Explicit argument 
obj.f: -> $n { say "Hi {$n}" }  # Explicit argument, no parenthesis 
obj.f: { say "Hi {$^n}" }       # Implicit argument, no parenthesis 

* Slurpy params / argument expansion

In Ruby you can declare an argument to slurp the remainder of the passed parameters into an array using a * prefix. It works the same way in Perl 6:

def foo(*args); puts "I got #{args.length} args!"end # Ruby 
sub foo(*@args{ say "I got #{@args.elems} args!" }   # Perl 6 

You might want to expand an array into a set of arguments. In Perl 6 this is also done using the * prefix:

args = %w(a b c)         # Ruby 
my @args = <a b c>       # Perl 6 

Perl 6 has many more advanced ways of passing parameters and receiving arguments, see Signatures and Captures.


Perl 6 additionally uses "twigils", which are further indicators about the variable and go between the sigil and the rest of the variable name. Examples:

$foo     # Scalar with no twigil 
$!foo    # Private instance variable 
$.foo    # Instance variable accessor 
$*foo    # Dynamically scoped variable 
$^foo    # A positional (placeholder) parameter to a block 
$:foo    # A named parameter 
$=foo    # POD (documentation) variables 
$?FILE   # Current source filename. The ? twigil indicates a compile-time value 
$~foo    # Sublanguage seen by parser, uncommon 

Though each of these examples use the $ sigil, most could use @ (Positional) or % (Associative).

: Symbols

Perl 6 generally uses strings in the places where Ruby uses symbols. A primary example of this is in hash keys.

address[:joe][:street# Typical Ruby nested hash with symbol keys 
%address<joe><street>  # Typical Perl 6 nested hash with string keys 

Perl 6 has colon-pair syntax, which can sometimes look like Ruby symbols.

:age            # Ruby symbol 
# All of these are equivalent for Perl 6 
:age            # Perl 6 pair with implicit True value 
:age(True)      # Perl 6 pair with explicit True value 
age => True     # Perl 6 pair using arrow notation 
"age" => True   # Perl 6 pair using arrow notation and explicit quotes 

You could probably get away with using a colon-pair without an explicit value and pretend that it is a Ruby symbol a lot of the time, but it isn't idiomatic Perl 6.


Many operators have a similar usage in both Ruby and Perl 6:

You may use $x++ instead of x += 1 as a shortcut for incrementing a variable. This can be used as a pre-increment ++$x (increment, return new value) or post-increment $x++ (increment, return old value).

You may use $x-- instead of x -= 1 as a shortcut for decrementing a variable. This can be used as a pre-decrement --$x (decrement, return new value) or post-decrement $x-- (decrement, return old value).

== != < > <= >= Comparisons

Comparisons in Perl 6 are separated between numeric and string to avoid common errors.

For example, using == tries to convert the values to numbers, and eq tries to convert the values to strings.

<=> Three-way comparisons

In Ruby, the <=> operator returns -1, 0, or 1. In Perl 6, they return Order::Less, Order::Same, or Order::More.

<=> forces numeric context for the comparison.

leg ("Less, Equal, or Greater?") forces string context for the comparison.

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

~~ Smart-match operator

This is a very common matching operator which doesn't exist in Ruby. Here are some examples:

say "match!" if $foo ~~ /bar/;      # Regex match 
say "match!" if $foo ~~ "bar";      # String match 
say "match!" if $foo ~~ :(IntStr# Signature match (destructure) 

See S03/Smart matching

& | ^ Numeric Bitwise ops

& | ^ Boolean ops

In Perl 6, these 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)

&. Conditional chaining operator

Ruby uses the &. operator to chain methods without raising an error if one invocation returns nil. In Perl 6 use .? for the same purpose.

<< >> Numeric shift left, right ops, shovel operator

Replaced by +< and +> .

puts 42 << 3  # Ruby 
say  42 +< 3# Perl 6 

Note that Ruby often uses the << operator as the "shovel operator", which is similar to .push. This usage isn't common in Perl 6.

=> and : Key-Value Separators

In Ruby, => is used in the context of key/value pairs for Hash literal declaration and parameter passing. : is used as a shorthand when the left side is a symbol.

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

If you are using => in a hash literal, then the usage is very similar:

hash = { "AAA" => 1"BBB" => 2 }  # Ruby, though symbol keys are more common 
my %hash = ( AAA => 1BBB => 2 ); # Perl 6, uses ()'s though {} usually work 

? : Ternary operator

In Perl 6, this is spelled with two question marks instead of one question mark, and two exclamation points instead of one colon. This deviation from the common ternary operators disambiguates several situations and makes the false-case stand out more.

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

+ String Concatenation

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

$food = 'grape' + 'fruit'  # Ruby 
$food = 'grape' ~ 'fruit'# Perl 6 

String interpolation

In Ruby, "#{foo}s" deliminates a block embedded in a double-quoted string. In Perl 6 drop the # prefix: "{$foo}s". As in Ruby, you can place arbitrary code into the embedded block and it will be rendered in string context.

Simple variables can be interpolated into a double-quoted string without using the block syntax:

# Ruby 
name = "Bob"
puts "Hello! My name is #{name}!"
# Perl 6 
my $name = "Bob"
say "Hello! My name is $name!"

The result of an embedded block in Ruby uses .to_s to get string context. Perl 6 uses .Str, or .gist for the same affect.

Compound Statements


if elsif else unless

This work very similarly between Ruby and Perl 6, but Perl 6 uses { } to clearly delineate the blocks.

# Ruby 
if x > 5
    puts "Bigger!"
elsif x == 5
    puts "The same!"
    puts "Smaller!"
# Perl 6 
if x > 5 {
    say "Bigger!"
} elsif x == 5 {
    puts "The same!"
} else {
    puts "Smaller!"

Binding the conditional expression to a variable is a little different:

if x = dostuff(); ...end   # Ruby 
if dostuff() -> $x {...}     # Perl 6, block-assignment uses arrow 

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


The Perl 6 given-when construct is like a chain of if-elsif-else statements or like the case-when construct in Ruby. A big difference is that Ruby uses the == comparison for each condition, but Perl 6 uses the more general smart-match ~~ operator.

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.


while until

Mostly unchanged; parentheses around the conditions are 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 x = dostuff(); ...end    # Ruby 
while dostuff() -> $x {...}      # Perl 6 

for .each

for loops are rare in Ruby, instead we typically use .each on an enumerable. The most direct translation to Perl 6 would be to use .map for both .each and .map, but we typically use a for loop directly.

# Ruby for loop 
for n in 0..5
    puts "n: #{n}"
# Ruby, more common usage of .each 
(0..5).each do |n|
    puts "n: #{n}"
# Perl 6 
for 0..5 -> $n {
    say "n: $n";
# Perl 6, misusing .map 
(0..5).map: -> $n {
    say "n: $n";

In Ruby, the iteration variable for .each is a copy of the list element, and modifying it does nothing to the original list. Note that it is a copy of the REFERENCE, so you can still change the values to which it refers.

In Perl 6, that alias is read-only (for safety) and thus behaves exactly like Ruby, unless you change -> to <->.

cars.each { |car| ... }    # Ruby; read-only reference 
for @cars  -> $car   {...} # Perl 6; read-only 
for @cars <-> $car   {...} # Perl 6; read-write 

Flow Interruption statements

Same as Ruby:

This is last in Perl 6.

Regular Expressions ( Regex / Regexp )

Regular expressions in Perl 6 are significantly different, and more powerful, than in Ruby. By default whitespace is ignored and all characters must be escaped, for example. Regexes can be easily combined and declared in ways to build efficient grammars.

There are many powerful features of Perl 6 regexes, especially defining entire grammars using the same syntax. See Regexes and Grammars.

.match method and =~ operator

In Ruby, regex matches can be done against a variable using the =~ regexp match operator or the .match method. In Perl 6, the ~~ smartmatch op is used instead, or the .match method.

next if line   =~ /static/   # Ruby 
next if $line  ~~ /static/;  # Perl 6 
next if line  !~  /dynamic/ ; # Ruby 
next if $line !~~ /dynamic/ ; # Perl 6 
next if line.match(/static/)    # Ruby 
next if $line.match(/static/);  # Perl 6 

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

.sub and .sub!

In Perl 6 you typically use the s/// operator to do regex substitution.

fixed = line.sub(/foo/'bar')        # Ruby, non-mutating 
my $fixed = $line.subst(/foo/'bar'# Perl 6, non-mutating 
line.sub!(/foo/'bar')   # Ruby, mutating 
$line ~~ s/foo/bar/;      # Perl 6, mutating 

Regex options

Move any options 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 # Ruby 
next if $line ~~ m:i/static/# Perl 6 

Whitespace is ignored, most things must be quoted

In order to aid in readability and reusability, whitespace is not significant in Perl 6 regexes.

/this is a test/ # Ruby, boring string 
/this.*/         # Ruby, possibly interesting string 
/ this " " is " " a " " test / # Perl 6, each space is quoted 
/ "this is a test" / # Perl 6, quoting the whole string 
/ this .* /          # Perl 6, possibly interesting string 

Special matchers generally fall under the <> syntax

There are many cases of special matching syntax that Perl 6 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 Longest Token Match (LTM), which decides which alternation wins an ambiguous match based off of a set of rules, rather than about which was written first in the regex.

To avoid the new logic, change any | in your Ruby regex to a ||.

File-related operations

Reading the lines of a text file into an array

Both Ruby and Perl 6 make it easy to read all of the lines in a file into a single variable, and in both cases each line has the newline removed.

lines = File.readlines("file")   # Ruby 
my @lines = "file".IO.lines;     # Perl 6, create an IO object from a string 

Iterating over the lines of a text file

Reading the entire file into memory isn't recommended. The .lines method in Perl 6 returns a lazy sequence, but assigning to an array forces the file to be read. It is better to iterate over the results:

# Ruby 
File.foreach("file"do |line|
    puts line
# Perl 6 
for "file".IO.lines -> $line {
    say $line

Object Orientation

Basic classes, methods, attributes

Classes are defined similarly between Ruby and Perl 6, using the class keyword. Ruby uses def for methods, whereas Perl 6 uses method.

# Ruby 
class Foo
    def greet(name)
        puts "Hi #{name}!"
# Perl 6 
class Foo {
    method greet($name{
        say "Hi $name!"

In Ruby you can use an attribute without declaring it beforehand, and you can tell it is an attribute because of the @ sigil. You can also easily create accessors using attr_accessor and it's variants. In Perl 6 you use a has declaration and a variety of sigils. You can use the ! twigil for private attributes or . to create an accessor.

# Ruby 
class Person
    attr_accessor :age    # Declare .age as an accessor method for @age 
    def initialize
        @name = 'default' # Assign default value to private instance var 
# Perl 6 
class Person
    has $.age;              # Declare $!age and accessor methods 
    has $!name = 'default'# Assign default value to private instance var 

Creating a new instance of the class uses the .new method. In Ruby you must manually assign instance variables as needed inside initialize. In Perl 6 you get a default constructor that accepts key/value pairs of accessor attributes, and can do further setup in the BUILD method. Like with Ruby, you can override new itself for more advanced functionality, but this is rare.

# Ruby 
class Person
    attr_accessor :name:age
    def initialize(attrs)
        @name = attrs[:name|| 'Jill'
        @age  = attrs[:age|| 42
        @birth_year = - @age
p = Person.newname: 'Jack'age: 23 )
# Perl 6 
class Person
    has $.name = 'Jill';
    has $.age  = 42;
    has $!birth_year;
    method BUILD {
        $!birth_year = now.Date.year - $.age;
p = Person.newname => 'Jack'age => 23 )

Private Methods

Private methods in Perl 6 are declared with a ! prefixed in their name, and are invoked with a ! instead of a ..

# Ruby 
class Foo
    def visible
        puts "I can be seen!"
    def hidden
        puts "I cannot easily be called!"
# Perl 6 
class Foo {
    method visible {
        say "I can be seen!"
    method !hidden {
        say "I cannot easily be called!"

An important note is that in Ruby child objects can see parent private methods (so they are more like "protected" methods in other languages). In Perl 6 child objects cannot call parent private methods.

Going Meta

Here are a few examples of meta-programming. Note that Perl 6 separates the meta-methods from the regular methods.

person =       # Ruby, create a new person 
my $person =   # Perl 6, create a new person 
person.class              # Ruby, returns Person (class) 
$person.WHAT              # Perl 6, returns Person (class) 
person.methods            # Ruby 
$person.^methods          # Perl 6, using .^ syntax to access meta-methods 
person.instance_variables # Ruby 
$person.^attributes       # Perl 6 

Like Ruby, in Perl 6, everything is an object, but not all operations are equivalent to .send. Many operators are global functions that use typed multi-dispatch (function signatures with types) to decide which implementation to use.

5.send(:+3)    # => 8, Ruby 
&[+](53)       # => 8, Perl 6, reference to infix addition operator 
&[+].^candidates # Perl 6, lists all signatures for the + operator 

See Meta-Object Protocol for lots of further details.

Environment variables

Perl module library path

In Ruby, one of the environment variables to specify extra search paths for modules is RUBYLIB.

$ RUBYLIB="/some/module/lib" ruby program.rb

In Perl 6 this is similar, you merely needs to change the name. As you probably guessed, you just need to use PERL6LIB:

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

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

# Ruby and Perl 6 
use lib '/some/module/lib';


Importing specific functions from a module

In Ruby there is no built-in way to selectively import/export methods from a module.

In Perl 6 you 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# remainder of the file is in module Bar { ... } 
sub foo($ais export { say "foo $a" }
sub bar($bis 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 you tries to use baz an "Undeclared routine" error is raised at compile time.

Some modules allow for selectively importing functions, which would look like:

use Bar <foo># Import only foo 
foo(1);        #=> "foo 1" 
bar(2);        # Error! 

OptionParser, parsing command-line flags

Command line argument switch parsing in Perl 6 is done by the parameter list of the MAIN subroutine.

# Ruby 
require 'optparse'
options = {} do |opts|
    opts.banner = 'Usage: example.rb --length=abc'
    opts.on("--length""Set the file"do |length|
        raise "Length must be > 0" unless length.to_i > 0
        options[:length= length
    opts.on("--filename""Set the file"do |filename|
        options[:file= filename
    opts.on("--verbose""Increase verbosity"do |verbose|
        options[:verbose= true
puts options[:length]
puts options[:filename]
puts 'Verbosity ', (options[:verbose? 'on' : 'off')
ruby example.rb --filename=foo --length=42 --verbose
    Verbosity on
ruby example.rb --length=abc
    Length must be > 0
# Perl 6 
sub MAIN ( Int :$length where * > 0:filename = 'file.dat'Bool :$verbose ) {
    say $length;
    say $data;
    say 'Verbosity ', ($verbose ?? 'on' !! '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.

RubyGems, External Libraries

See, where a growing number of Perl 6 libraries are available along with the tools to manage them.

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.

You can experiment with Inline::Ruby to call existing Ruby code from your Perl 6 programs. This uses an embedded instance of the ruby interpreter to run Ruby code called from your Perl 6 script. Note that this is an EXPERIMENTAL library. You can similarly call other language's libraries with Inline::Perl5, Inline::Python, and others.