Raku Colonoscopy

Perl 6 → Raku This article has been moved from «perl6.eu» and updated to reflect the language rename in 2019.

I promise, this will not hurt. Much...

In this article we'll look into colons in Raku, where to place them, and what they mean.

Sigils

What Perl Raku Raku Alternate Syntax Array @a @a Array element $a[0] @a[0] Array slice @a[0,1] @a[0,1] Hash %h %h Hash element $h{'a'} %h{'a'} %h<a> Hash slice @h{'a', 'b'} %h{'a', 'b'} %h<a b>

Raku also has Twigils, a secondary character between the sigil and the variable name, that slightly alters the meaning of the variable. We'll not get into that in this article (with one exception, the colon).

See docs.raku.org/language/variables for more information about Variables, Sigils and Twigils.

Namespaces

::

Let us say that the have a module Foo with a procedure bar and a variable $bar . We can access them like this (if the module has made them available for outside code):

use Foo; Foo::bar; # A procedure call say $Foo::bar; # Accessing a variable

We can also use namespaces directly (but it isn't recommended):

my $a = 10; my $FOO::BAR::a = 20; say $a + $FOO::BAR::a; # -> 30

Two colons on their own work as well, and gives us access to meta information about the current scope (as far as I understand it):

> say :: PseudoStash.new((!UNIT_MARKER => (!UNIT_MARKER), $=pod => [], $?PACKAGE => (GLOBAL), $_ => (Any), ::?PACKAGE => (GLOBAL), EXPORT => (EXPORT), GLOBALish => (GLOBAL)))

See docs.raku.org/type/PseudoStash for information about the PseudoStash type, but be prepared to be (or stay) confused.

Versioned Modules

module Foo:ver<1.00>:auth { ... }

Inline::Perl5

use Foo::Bar:from<Perl5>;

This works for other languages as well. See modules.raku.org/search/?q=inline for a list of available languages. The support may be incomplete, so read the documentation.

Labels

We cannot use it to jump around in the code, as Raku doesn't have a goto command. But we can use it to jump out of loops (or around in them), with the last , next or redo commands.

Consider the last command without using a label:

for 1 .. 10 -> $a { for 1 .. 10 -> $b { last if $b == 5; say "$a $b"; } }

The last will exit the inner loop if the condition is met. We can get it to act on another level if we use a label:

outer: for 1 .. 10 -> $a { inner: for 1 .. 10 -> $b { last outer if $b == 5; say "$a $b"; } }

This time it exits the outer loop (and the program, as there isn't any more code to execute) when the condition is met.

Upper Case letters are normally used for labels, but this will cause an error if you happen to choose a name that is already in use internally by Raku. The label itself isn't a problem, as the trailing colon tells the compiler that it is a label. The usage, where it is used as a bareword causes the problem, and there is no way to fix it.

Some examples:

OUTER , which seems perfectly logical as a label name, will give the run time error («Cannot resolve caller next(OUTER:U); ...»), as OUTER is a built-in package name and Raku isn't clever enough to spot that it is used as a label in this case.

, which seems perfectly logical as a label name, will give the run time error («Cannot resolve caller next(OUTER:U); ...»), as is a built-in package name and Raku isn't clever enough to spot that it is used as a label in this case. LAST isn't equally tempting to use, but will give the compilation error («Missing block»), as LAST is a Phaser, expecting a block after it.

See docs.raku.org/language/packages#Pseudo-packages for more information about Package Names to avoid.

See docs.raku.org/language/phasers for more information about Phasers.

If you get an error message when using a label, even if you have avoided reserved packagae Names and Phasers, try changing the name by e.g. appending a digit to it. Or use lower case letters.

Numbers

my $b = :2<11110000>; # -> 240 ## A binary (base 2) number my $a = :16<FF>; # -> 255 ## A hexadecimal (base 16) number

Note that we can use parens and quotes if we want to make it look like a procedure call:

my $b = :2("11110000"); # -> 240 ## A binary (base 2) number

Pair

We can construct a Pair in several ways, using the «fat arrow» ( => ):

Pair('key' => 'value') ('key' => 'value') 'key' => 'value' key => 'value' # As long as the key doesn't contain spaces.

We don't have to use the «fat arrow»:

Pair.new('key', 'value')

We can use the special colon syntax, as long as the key doesn't contain spaces:

:key<value> # The same as «key => 'value'»

We can use parens as well:

:foo(127) # The same as «foo => 127»

If the key uses letters, and the value digits only, we can do this:

:127foo # The same as «foo => 127»

If the value is a Boolean, we can shorten it even further:

:key # The same as «key => True» :!key # The same as «key => False»

Variables

$variable

Before the sigil ( :$variable )

) Between the sigil and variable name ( $:variable )

) After the variable name ( $variable: )

:$variable

sub foo (:$one, :$two) { return $one + 2 * $two; } say foo(one => 12, two => 3); # -> 18 say foo(two => 3, one => 12); # -> 18

The order doesn't matter.

If we give the variable the same name as the argument, we can use a short form (shown on the last line):

sub foo (:$one, :$two) { return $one + 2 * $two; } my $one = 12; my $two = 3; say foo(one => $one, two => $two); # -> 18 say foo(:$one, :$two); # -> 18

Named variables are useful when we have several parameters, as it is possible to mix up the order with normal positional parameters. It is also handy when we have optional parameters, as we can specify just the one(s) we want to use.

If the value of the named argument is True , we can drop the explicit value:

sub debug (:$debug) { say "Debug" if $debug; return 32; } my $x = foo(:debug);

And we can negate it (with an exclamation mark between the colon and the name), to pass False :

my $x = foo(:!debug);

Named variables are optional by default, but we can make them mandatory by adding a trailing ! (exclamation mark) in the procedure head.

We can turn any variable into a Pair , with the variable name as the key:

my $age = 14; my $p = :$age; say $p; # -> age => 10

$:variable

sub foo { return $:one + 2 * $:two; } say foo(one => 12, two => 3); # -> 18

Note that the names must match - and it will only work if the procedure is specified without a signature (argument list)!

This is the one where the colon is a Twigil.

(We can also use placeholder variables for positional arguments, with the ^ Twigil. See docs.raku.org/language/variables#The_^_twigil for more information

$variable:

$foo

bar

$foo.bar;

But we can also use a more procedure like syntax, like this:

bar($foo:);

Method Call with arguments

$foo

bar

class foo { ...; method bar ($abc, $def) { ... } } my $foo1 = foo.new; $foo1.bar(1, 2);

It isn't possible to skip the parens (as we can with a procedure call), but we can use this colon syntax:

$foo1.bar: 1, 2;

The procedure like syntax works here as well, with parens:

bar($foo1: 1, 2);

:= (Binding)

Binding skips the container, and works directly with the value. When used on a value, this gives a constant:

my $a := 10; say $a; # -> 10; $a++; # Fails. Cannot resolve caller postfix:(Int:D); the following candidates match the type but require mutable argument ...

If we bind to another variable, we get an alias:

my $a = 10; my $b := $a; say $b; # -> 10; $a++; say $b; # -> 11; $b++; say $a; # -> 12;

Incrementing $b works, because it has been binded to the container we got from $a .

=:= (Container Identity)

True

my $a = 10; my $b = 10; say $a =:= $b; # -> False my $c := $a; say $a =:= $c; # -> True

It works even if we don't have any containers (as they are bound to the same value):

my $a := 10; my $b := 10; say $a =:= $b; # -> True

::?CLASS

class FOO { method bar { return ::?CLASS; } } my FOO $foo = FOO.new; say $foo.bar; # -> (FOO)

It fails if we are not in a class:

say ::?CLASS; ===SORRY!=== Error while compiling: No such symbol '::?CLASS'

::($variable)

my ($a1, $a2, $a3, $a4, $a5, $a6, $a7, $a8, $a9, $a10) = <12 9 8 27 75 5 18 21 36 99>; say "$_: ", ::{ '$a' ~ $_ } for 1 .. 10;

The single quotes are essential, as we definitely do not want the string to be interpolated (as $a doesn't exist).

Use defined if you want to check that the variable exists (is defined), as a «normal» lookup doesn't fail:

say ::{'$a11'}; # -> Nil say ::{'$a11'}.defined; # -> False say ::{'$a10'}.defined; # -> True

We can use it to look up variables in other scopes as well. See docs.raku.org/language/packages#Looking_up_names for more information about this topic.

::= (Read Only Binding)

Commercial Break