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.
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.
::
) is used to address a name (variable,
procedure or class) in another namespace.
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):
File: namespace
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.
module Foo:ver<1.00>:auth { ... }
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.
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.
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.
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
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»
$variable
):
:$variable
)
$: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
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
$foo
and want to call a method
bar
on it, the usual way is this:
$foo.bar;
But we can also use a more procedure like syntax, like this:
bar($foo:);
$foo
and want to call a method bar
on it with some arguments, the usual way is this:
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 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
.
True
if both
argumentes are bound to the same container:
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 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'
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.