Raku (programming language)


Raku is a member of the Perl family of programming languages. Formerly known as Perl 6, it was renamed in October 2019. Raku introduces elements of many modern and historical languages. Compatibility with Perl was not a goal, though a compatibility mode is part of the specification. The design process for Raku began in 2000.

History

The Raku design process was first announced on 19 July 2000, on the fourth day of that year's Perl Conference, by Larry Wall in his State of the Onion 2000 talk. At that time, the primary goals were to remove "historical warts" from the language; "easy things should stay easy, hard things should get easier, and impossible things should get hard"; a general cleanup of the internal design and APIs. The process began with a series of requests for comments or "RFCs". This process was open to all contributors, and left no aspect of the language closed to change.
Once the RFC process was complete, Wall reviewed and classified each request. He then began the process of writing several "Apocalypses", a term which means "revealing". While the original goal was to write one Apocalypse for each chapter of Programming Perl, it became obvious that, as each Apocalypse was written, previous Apocalypses were being invalidated by later changes. For this reason, a set of Synopses were published, each one relating the contents of an Apocalypse, but with any subsequent changes reflected in updates. Today, the Raku specification is managed through the "roast" testing suite, while the Synopses are kept as a historical reference.
There are also a series of Exegeses written by Damian Conway that explain the content of each Apocalypse in terms of practical usage. Each Exegesis consists of code examples along with discussion of the usage and implications of the examples.
There are three primary methods of communication used in the development of Raku today. The first is the IRC channel on freenode. The second is a set of mailing lists on The Perl Foundation's servers at . The third is the Git source code repository hosted at https://github.com/raku.

Initial goals and implications

The major goal Wall suggested in his initial speech was the removal of historical warts. These included the confusion surrounding sigil usage for containers; the ambiguity between the select functions; the syntactic impact of bareword filehandles. There were many other problems that Perl programmers had discussed fixing for years and these were explicitly addressed by Wall in his speech.
An implication of these goals was that Perl 6 would not retain backwards compatibility with the existing Perl codebase. This meant that some code which was correctly interpreted by a Perl 5 compiler would not be accepted by a Perl 6 compiler. Since retaining backwards compatibility is a common goal when enhancing software, the break in compatibility between Perl 5 and Perl 6 had to be stated explicitly. The distinction between Perl 5 and Perl 6 became so large that eventually Perl 6 was renamed Raku.
Over the years, Raku has undergone several alterations in its direction. The introduction of concepts from Python and Ruby were early influences. Furthermore, since Pugs - the first interpreter able to run Raku - was written in the Haskell programming language, many functional programming influences were absorbed by the Raku design team.

Mascot

The language's mascot is "Camelia, the Raku bug".
Her name is a nod to the camel mascot associated with Perl, and her form, in the pun-loving tradition of the Perl community, is a play on "software bug". Spiral designs embedded in her butterfly-like wings resemble the characters "P6", the favored nickname for Perl 6, and off-center eye placement is an intentional pun on "Wall-eyed".
One of the goals behind the lively and colorful design of the logo was to discourage misogyny in the community and for it to be an opportunity for those of "masculine persuasion" to show their sensitive side.

Implementations

, only the Rakudo implementation is under active development. No implementation will be designated as the official Raku implementation; rather, "Raku is anything that passes the official test suite."
Rakudo Perl 6 targets a number of virtual machines, such as MoarVM, the Java Virtual Machine, and JavaScript. MoarVM is a virtual machine built especially for Rakudo and the NQP Compiler Toolchain. There is a layer between Raku and the virtual machines called Not Quite Perl 6, or NQP, which implements Raku rules for parsing Raku, as well as an abstract syntax tree and backend-specific code generation. Large portions of Rakudo are written in Raku itself, or in its subset NQP. Rakudo is not a completely self-hosting implementation, nor are there concrete plans at this point to make Rakudo a bootstrapping compiler.

Historical implementations

was an initial implementation of Perl 6 written in Haskell. Pugs used to be the most advanced implementation of Perl 6, but since mid 2007 it is mostly dormant. As of November 2014 Pugs was not being actively maintained.
In 2007, v6-MiniPerl6 and its reimplementation, v6-KindaPerl6 were written as a means to bootstrap the Perl-6.0.0 STD, using Perl 5. The STD is a full grammar for Perl 6 and is written in Perl 6. In theory, anything capable of parsing the STD and generating executable code is a suitable bootstrapping system for Perl 6. kp6 is currently compiled by mp6 and can work with multiple backends. mp6 and kp6 are not full Perl 6 implementations and are designed only to implement the minimum featureset required to bootstrap a full Perl 6 compiler.
Yapsi is a Perl 6 compiler and runtime written in Perl 6 itself. As a result, it requires an existing Perl 6 interpreter, such as one of the Rakudo Star releases, in order to run.
Niecza, another major Perl 6 implementation effort, focused on optimization and efficient implementation research. It targets the Common Language Infrastructure.

Module system

The Raku specification requests that modules be identified by name, version, and authority. It is possible to load only a specific version of a module, or even two modules of the same name that differ in version or authority. As a convenience, aliasing to a short name is provided.
CPAN, the Perl module distribution system, does not yet handle Raku modules. Instead a prototype module system is in use.

Major changes from Perl

Perl and Raku differ fundamentally, though in general the intent has been to "keep Raku Perl", so that Raku is clearly "a Perl programming language". Most of the changes are intended to normalize the language, to make it easier for novice and expert programmers alike to understand, and to make "easy things easier and hard things more possible".

A specification

A major non-technical difference between Perl and Raku is that Raku began as a specification. This means that Raku can be re-implemented if needed, and it also means that programmers do not have to read the source code for the ultimate authority on any given feature. The official documentation is not considered authoritative and only describes the behavior of the actual Perl interpreter informally. Any discrepancies found between the documentation and the implementation may lead to either being changed to reflect the other, a dynamic which drives the continuing development and refinement of the Perl releases.

A type system

In Raku, the dynamic type system of Perl has been augmented by the addition of static types. For example:

my Int $i = 0;
my Rat $r = 3.142;
my Str $s = "Hello, world";

However, static typing remains optional, so programmers can do most things without any explicit typing at all:

my $i = "25" + 10; # $i is 35

Raku offers a gradual typing system, whereby the programmer may choose to use static typing, use dynamic typing, or mix the two.

Formal subroutine parameter lists

Perl defines subroutines without formal parameter lists at all. Subroutine arguments passed in are aliased into the elements of the array @_. If the elements of @_ are modified, the changes are reflected in the original data.
Raku introduces true formal parameters to the language. In Raku, a subroutine declaration looks like this:

sub do_something

As in Perl, the formal parameters are aliases to the actual parameters, but by default, the aliases are constant so they cannot be modified. They may be declared explicitly as read-write aliases for the original value or as copies using the is rw or is copy directives respectively should the programmer require them to be modified locally.

Parameter passing modes

Raku provides three basic modes of parameter passing: positional parameters, named parameters, and slurpy parameters.
Positional parameters are the typical ordered list of parameters that most programming languages use. All parameters may also be passed by using their name in an unordered way. Named-only parameters can only be passed by specifying its name, i.e. it never captures a positional argument. Slurpy parameters are Raku's tool for creating variadic functions. A slurpy hash will capture remaining passed-by-name parameters, whereas a slurpy array will capture remaining passed-by-position parameters.
Here is an example of the use of all three parameter-passing modes:

sub somefunction
somefunction; # $a=1, $b=2, $d=3, @e=

Positional parameters, such as those used above, are always required unless followed by ? to indicate that they are optional. Named parameters are optional by default, but may be marked as required by adding ! after the variable name. Slurpy parameters are always optional.

Blocks and closures

Parameters can also be passed to arbitrary blocks, which act as closures. This is how, for example, for and while loop iterators are named. In the following example, a list is traversed, 3 elements at a time, and passed to the loop's block as the variables, $a, $b, $c.

for @list -> $a, $b, $c

This is generally referred to as a "pointy sub" or "pointy block", and the arrow behaves almost exactly like the sub keyword, introducing an anonymous closure.

Sigil invariance

In Perl, sigils - the punctuation characters that precede a variable name - change depending on how the variable is used:
# Perl code
my array = ;
my $element = array; # $element equals 'b',
my @extract = array; # @extract equals
my $element = array; # 'b' comes with a warning
In Raku, sigils are invariant, which means that they do not change based on whether it is the array or the array element that is needed:
# Raku code
my array = 'a', 'b', 'c';
my $element = array; # $element equals 'b'
my @extract = array; # @extract equals
my @extract = array; # @extract equals
The variance in Perl is inspired by number agreement in English and many other natural languages:
"This apple." # $a CORRECT
"These apples." # @a CORRECT
"This third apple." # $a CORRECT
"These third apple." # @a WRONG
However, this conceptual mapping breaks down when references come into play, since they may refer to data structures even though they are scalars. Thus, dealing with nested data structures may require an expression of both singular and plural form in a single term:

  1. Perl code: retrieve a list from the leaf of a hash containing hashes that contain arrays
my @trans_verbs = @;

This complexity has no equivalent either in common use of natural language or in other programming languages, and it causes high cognitive load when writing code to manipulate complex data structures. Compare this with Raku:

  1. Raku code: retrieve a list from the leaf of a hash containing hashes that contain arrays
my @trans_verbs = %dictionary<>;

Object-oriented programming

Perl supports object-oriented programming via a mechanism known as blessing. Any reference can be blessed into being an object of a particular class. A blessed object can have methods invoked on it using the "arrow syntax" which will cause Perl to locate or "dispatch" an appropriate subroutine by name, and call it with the blessed variable as its first argument.
While extremely powerful, it makes the most common case of object orientation, a struct-like object with some associated code, unnecessarily difficult. In addition, because Perl can make no assumptions about the object model in use, method invocation cannot be optimized very well.
In the spirit of making the "easy things easy and hard things possible", Raku retains the blessing model and supplies a more robust object model for the common cases. For example, a class to encapsulate a Cartesian point could be defined and used this way:

class Point is rw
my $point = Point.new;
say "Point's location: ';
  1. OUTPUT: Point's location:
  2. Changing x and y :
$point.x = 3;
$point.y = 4;
say "Point's location: ';
  1. OUTPUT: Point's location:
my $other-point = Point.new;
$point.distance; #=> 10
$point.distance-to-center; #=> 5

The dot replaces the arrow in a nod to the many other languages that have coalesced around dot as the syntax for method invocation.
In the terminology of Raku, $.x is called an "attribute". Some languages call these fields or members. The method used to access an attribute is called an "accessor". An auto-accessor method is a method created automatically and named after the attribute's name, as the method x is in the example above. These accessor functions return the value of the attribute. When a class or individual attribute is declared with the is rw modifier, the auto-accessors can be passed a new value to set the attribute to, or it can be directly assigned to as an lvalue. Auto-accessors can be replaced by user-defined methods, should the programmer desire a richer interface to an attribute. Attributes can only be accessed directly from within a class definition via the $! syntax regardless of how the attributes are declared. All other access must go through the accessor methods.
The Raku object system has inspired the Moose framework that introduces many of Raku's OOP features to Perl.

Inheritance, Roles and Classes

Inheritance is the technique by which an object or type can re-use code or definitions from existing objects or types. For example, a programmer may want to have a standard type but with an extra attribute. Inheritance in other languages, such as Java, is provided by allowing Classes to be sub-classes of existing classes.
Raku provides for inheritance via Classes, which are similar to Classes in other languages, and Roles.
Roles in Raku take on the function of interfaces in Java, mixins in Ruby, and traits in the Smalltalk variant Squeak. These are much like classes, but they provide a safer composition mechanism. These are used to perform composition when used with classes rather than adding to their inheritance chain. Roles define nominal types; they provide semantic names for collections of behavior and state. The fundamental difference between a role and a class is that classes can be instantiated; roles are not.
Although Roles are distinct from Classes, it is possible to write Raku code that directly instantiates a Role or uses a Role as a type object, Raku will automatically create a class with the same name as the role, making it possible to transparently use a role as if it were a class.
Essentially, a role is a bundle of methods and attributes that can be added to a class without using inheritance. A role can even be added to an individual object; in this case, Raku will create an anonymous subclass, add the role to the subclass, and change the object's class to the anonymous subclass.
To illustrate the difference between a Class and a Role, consider the following. A Dog is a Mammal because dogs inherit certain characteristics from Mammals, such as mammary glands and a backbone. On the other hand, dogs also may have one of several distinct types of behavior, and these behaviours may change over time. For example, a Dog may be a Pet, a Stray, or a Guide for the blind. However, these are sets of additional behaviors that can be added to a Dog. It is also possible to describe these behaviors in such a way that they can be usefully applied to other animals, for example, a Cat can equally be a Pet or Stray. Hence, Dog and Cat are both distinct from each other, while both remaining within the more general category Mammal. So Mammal is a Class and Dog and Cat are classes that inherit from Mammal. But the behaviours associated with Pet, Stray, and Guide are Roles that can be added to Classes, or objects instantiated from Classes.

class Mammal is Vertebrate
class Dog is Mammal
role Pet
role Stray
role Guide

Roles are added to a class or object with the does keyword. In order to show inheritance from a class, there is a different keyword is. The keywords reflect the differing meanings of the two features: role composition gives a class the behavior of the role, but doesn't indicate that it is truly the same thing as the role.

class GuideDog is Dog does Guide # Subclass composes role
my $dog = new Dog;
$dog does Guide; # Individual object composes role

Although roles are distinct from classes, both are types, so a role can appear in a variable declaration where one would normally put a class. For example, a Blind role for a Human could include an attribute of type Guide; this attribute could contain a Guide Dog, a Guide Horse, a Guide Human, or even a Guide Machine.

class Human
role Blind

Regular expressions

Perl's regular expression and string-processing support has always been one of its defining features. Since Perl's pattern-matching constructs have exceeded the capabilities of regular language expressions for some time, Raku documentation will exclusively refer to them as regexes, distancing the term from the formal definition.
Raku provides a superset of Perl features with respect to regexes, folding them into a larger framework called "rules" which provide the capabilities of context-sensitive parsing formalisms, as well as acting as a closure with respect to their lexical scope. Rules are introduced with the rule keyword which has a usage quite similar to subroutine definition. Anonymous rules can also be introduced with the regex keyword, or they can simply be used inline as regexps were in Perl via the m or s operators.
In Apocalypse 5, Larry Wall enumerated 20 problems with "current regex culture". Among these were that Perl's regexes were "too compact and 'cute'", had "too much reliance on too few metacharacters", "little support for named captures", "little support for grammars", and "poor integration with 'real' language".

Syntactic simplification

Some Perl constructs have been changed in Raku, optimized for different syntactic cues for the most common cases. For example, the parentheses required in control flow constructs in Perl are now optional:

if is_true

Also, the , operator is now a list constructor, so enclosing parentheses are no longer required around lists. The code

@array = 1, 2, 3, 4;

now makes @array an array with exactly the elements '1', '2', '3', and '4'.

Chained comparisons

Raku allows comparisons to "chain". That is, a sequence of comparisons such as the following is allowed:

if 20 <= $temperature <= 25

This is treated as if each left-to-right comparison were performed on its own, and the result is logically combined via the and operation.

Lazy evaluation

Raku uses the technique of lazy evaluation of lists that has been a feature of some functional programming languages such as Haskell:

@integers = 0..Inf; # integers from 0 to infinity

The code above will not crash by attempting to assign a list of infinite size to the array @integers, nor will it hang indefinitely in attempting to expand the list if a limited number of slots are searched.
This simplifies many common tasks in Raku including input/output operations, list transformations, and parameter passing.

Gather

Related to lazy evaluation is the construction of lazy lists using gather and take, behaving somewhat like generators in languages like Icon or Python.

my $squares = lazy gather for 0..Inf ;

$squares will be an infinite list of square numbers, but lazy evaluation of the gather ensures that elements are only computed when they are accessed.

Junctions

Raku introduces the concept of junctions: values that are composites of other values. In their simplest form, junctions are created by combining a set of values with junctive operators:

  1. Example for | Junction:
my $color = 'white';
unless $color eq 'white' | 'black' | 'gray' | 'grey'
  1. Example for & Junction:
my $password = 'secret!123';
if $password ~~ /<:alpha>/ & /<:digit>/ & /<:punct>/

| indicates a value which is equal to either its left- or right-hand arguments. & indicates a value which is equal to both its left- and right-hand arguments. These values can be used in any code that would use a normal value. Operations performed on a junction act on all members of the junction equally, and combine according to the junctive operator. So, ~ "s" would yield "apples"|"bananas". In comparisons, junctions return a single true or false result for the comparison. "any" junctions return true if the comparison is true for any one of the elements of the junction. "all" junctions return true if the comparison is true for all of the elements of the junction.
Junctions can also be used to more richly augment the type system by introducing a style of generic programming that is constrained to junctions of types:

subset Color of Any where RGB_Color | CMYK_Color;
sub get_tint

Macros

In low-level languages, the concept of macros has become synonymous with textual substitution of source-code due to the widespread use of the C preprocessor. However, high-level languages such as Lisp pre-dated C in their use of macros that were far more powerful. It is this Lisp-like macro concept that Raku will take advantage of. The power of this sort of macro stems from the fact that it operates on the program as a high-level data structure, rather than as simple text, and has the full capabilities of the programming language at its disposal.
A Raku macro definition will look like a subroutine or method definition, and it can operate on unparsed strings, an AST representing pre-parsed code, or a combination of the two. A macro definition would look like this:

macro hello

In this particular example, the macro is no more complex than a C-style textual substitution, but because parsing of the macro parameter occurs before the macro operates on the calling code, diagnostic messages would be far more informative. However, because the body of a macro is executed at compile time each time it is used, many techniques of optimization can be employed. It is even possible to entirely eliminate complex computations from resulting programs by performing the work at compile-time.

Identifiers

In Perl, identifier names can use the ASCII alphanumerics and underscores also available in other languages.
In Raku, the alphanumerics can include most Unicode characters.
In addition, hyphens and apostrophes can be used.
Using hyphens instead of underscores to separate words in a name leads to a style of coding called "kebab-casing" which is highly regarded
by two-finger typists.

Examples

Hello world

The hello world program is a common program used to introduce a language. In Raku, hello world is:

say 'Hello, world';

— though there is more than one way to do it.

Factorial

The factorial function in Raku, defined in a few different ways:

  1. Using recursion
sub fact
  1. Using recursion
sub fact
  1. Using recursion
sub fact
  1. Using the ternary operator
sub fact
  1. Using multiple dispatch
multi fact
multi fact
  1. Using the reduction metaoperator
multi fact
  1. Creating a factorial operator and using the reduction metaoperator
sub postfix:
  1. Using `state` declarator to create a memoized factorial
sub fact

Quicksort

is a well-known sorting algorithm. A working implementation using the functional programming paradigm can be succinctly written in Raku:

  1. Empty list sorts to the empty list
multi quicksort
  1. Otherwise, extract first item as pivot...
multi quicksort

Tower of Hanoi

is often used to introduce recursive programming in computer science. This implementation uses Raku's multi-dispatch mechanism and parametric constraints:

multi sub hanoi # No disk, so do not do anything
multi sub hanoi

Books

In the history of Raku there were two waves of book writing. The first wave followed the initial announcement of Perl 6 in 2000. Those books reflect the state of the design of the language of that time, and contain mostly outdated material as of today. The second wave, that followed the announcement of Version 1.0 in 2015, includes several books that have already been published and some others that are in the process of being written.

Books published before Perl 6 version 1.0 (known as version 6.c)

Also, a book dedicated to one of the first Perl 6 virtual machines, Parrot, was published in 2009.
There are a few reports from different authors about the new books that are going to be published soon, all based on the current version 1.0 of Perl 6.