🔬 75. my $x = $x in Perl 6

What happens if you’ll try to create a new variable and immediately initialise it by itself, as shown in the following test code:

my $x = $x;

This does not work (which is expected), but Perl 6 is so kind to the user  that it gives an error message prepared especially for this case:

===SORRY!=== Error while compiling:
Cannot use variable $x in declaration to initialize itself
------> my $x = $⏏x;
  expecting any of:
  term

Let us find the place in the code where the error message is triggered. This case is captured in the Grammar of Perl 6, at the place where variable is parsed:

token variable {
    . . .
    | <sigil>
      [ $<twigil>=['.^'] <desigilname=desigilmetaname>
        | <twigil>? <desigilname> ]
      [ <?{ !$*IN_DECL && $*VARIABLE && $*VARIABLE eq 
        $<sigil> ~ $<twigil> ~ $<desigilname> }>
          {
              self.typed_panic: 'X::Syntax::Variable::Initializer', 
              name => $*VARIABLE
          }
      ]?
    . . .
}

The condition to throw an exception is a bit wordy, but you can clearly see here that the whole variable name is checked, including both sigil and potential twigil.

The exception itself is located in src/core/Exception.pm6 (notice that file extensions were changed from .pm to .pm6 recently), and it is used only for the above case:

my class X::Syntax::Variable::Initializer does X::Syntax {
    has $.name = '<anon>';
    method message() {
        "Cannot use variable $!name in declaration to initialize itself"
    }
}

And that’s all for today. Rakudo Perl 6 sources can be really transparent sometimes! 🙂

🦋 74. Typed hashes in Perl 6

In Perl 6, you can restrict the content of a variable container by specifying its type, for example:

my Int $i;

There is only one value in a scalar variable. You can extend the concept to arrays and let its element to keep only integers, as it is done in the next example:

> my Int @i;
[]

> @i.push(42);
[42]

> @i.push('Hello');
Type check failed in assignment to @i;
expected Int but got Str ("Hello")
  in block <unit> at <unknown file> line 1

Hashes keeps pairs, so you can specify the type of both keys and values. The syntax is not deductible from the above examples.

First, let us announce the type of the value:

my Str %s;

Now, it is possible to have strings as values:

> %s<Hello> = 'World'
World

> %s<42> = 'Fourty-two'
Fourty-two

But it’s not possible to save integers:

> %s<x> = 100
Type check failed in assignment to %s;
expected Str but got Int (100)
  in block <unit> at <unknown file> line 1

(By the way, notice that in the case of %s<42> the key is a string.)

To specify the type of the second dimension, namely, of the hash keys, give the type in curly braces:

my %r{Rat};

This variable is also referred to as object hash.

Having this, Perl expects you to have Rat keys for this variable:

> %r<22/7> = pi
3.14159265358979

> %r
{22/7 => 3.14159265358979}

Attempts to use integers or strings, for example, fail:

> %r<Hello> = 1
Type check failed in binding to parameter 'key';
expected Rat but got Str ("Hello")
  in block <unit> at <unknown file> line 1

> %r{23} = 32
Type check failed in binding to parameter 'key';
expected Rat but got Int (23)
  in block <unit> at <unknown file> line 1

Finally, you can specify the types of both keys and values:

my Str %m{Int};

This variable can be used for translating month number to month names but not vice versa:

> %m{3} = 'March'
March

> %m<March> = 3
Type check failed in binding to parameter 'key';
expected Int but got Str ("March")
  in block <unit> at <unknown file> line 1

 

🔬73. Keys, values, etc. of hashes in Perl 6

Today, we will take a look at a few methods of the Hash class that return all hash keys or values or both:

> my %h = H => 'Hydrogen', He => 'Helium', Li => 'Lithium';
{H => Hydrogen, He => Helium, Li => Lithium}

> %h.keys;
(H Li He)

> %h.values;
(Hydrogen Lithium Helium)

> %h.kv;
(H Hydrogen Li Lithium He Helium)

While you may want to go directly to the src/core/Hash.pm6 file to see the definitions of the methods, you will not find them there. The Hash class is a child of Map, and all these methods are defined in src/core/Map.pm6. Getting keys and values is simple:

multi method keys(Map:D:) {
    Seq.new(Rakudo::Iterator.Mappy-keys(self))
}

multi method values(Map:D:) {
    Seq.new(Rakudo::Iterator.Mappy-values(self))
}

For the kv method, more work has to be done:

multi method kv(Map:D:) {
    Seq.new(class :: does Rakudo::Iterator::Mappy {
        has int $!on-value;

        method pull-one() is raw {
            . . .
        }
        method skip-one() {
            . . .
        }
        method push-all($target --> IterationEnd) {
            . . .
        }
    }.new(self))
}

As you see, the method returns a sequence that is built using an anonymous class implementing the Rakudo::Iterator::Mappy role. We already saw how this approach is used in combination with defining pull-one and push-all methods.

Let us look at another set of methods, pairs and antipairs. One of them is simple and straightforward:

multi method pairs(Map:D:) {
    Seq.new(self.iterator)
}

Another one is using an intermediate class:

multi method antipairs(Map:D:) {
    Seq.new(class :: does Rakudo::Iterator::Mappy {
        method pull-one() {
            . . .
        }
        method push-all($target --> IterationEnd) {
        . . .
        }
    }.new(self))
}

Both methods produce results of the same structure:

> %h.antipairs
(Hydrogen => H Lithium => Li Helium => He)

> %h.pairs
(H => Hydrogen Li => Lithium He => Helium)

 

🔬72. Superscripts in Perl 6

In Perl 6, you can use superscript indices to calculate powers of numbers, for example:

> 2⁵
32

> 7³
343

It also works with more than one digit in the superscript:

> 10¹²
1000000000000

You can guess that the above cases are equivalent to the following:

> 2**5
32
> 7**3
343

> 10**12
1000000000000

But the question is: How on Earth does it work? Let us find it out.

For the Numeric role, the following operation is defined:

proto sub postfix:<ⁿ>(Mu $, Mu $) is pure {*}
multi sub postfix:<ⁿ>(\a, \b) { a ** b }

Aha, that is what we need, and the superscript notation is converted to the simple ** operator here.

You can visualise what exactly is passed to the operation by printing the operands:

multi sub postfix:<ⁿ>(\a, \b) { 
    nqp::say('# a = ' ~ a);
    nqp::say('# b = ' ~ b);
    a ** b 
}

In this case, you’ll see the following output for the test examples above:

> 2⁵
# a = 2
# b = 5

> 10¹²
# a = 10
# b = 12

Now, it is time to understand how the postfix that extracts superscripts works. Its name, , written in superscript, should not mislead you. This is not a magic trick of the parser, this is just a name of the symbol, and it can be found in the Grammar:

token postfix:sym<ⁿ> {
    <sign=[⁻⁺¯]>? <dig=[⁰¹²³⁴⁵⁶⁷⁸⁹]>+ <O(|%autoincrement)>
}

You see, this symbol is a sequence of superscripted digits with an optional sign before them. (Did you think of a sign before we reached this moment in the Grammar?)

Let us try negative powers, by the way:

> say 4⁻³
# a = 4
# b = -3
0.015625

Also notice that the whole construct is treated as a postfix operator. It can also be applied to variables, for example:

> my $x = 9
9
> say $x²
# a = 9
# b = 2
81

So, a digit in superscript is not a part of the variable’s name.

OK, the final part of the trilogy, the code in Actions, which parses the index:

method postfix:sym<ⁿ>($/) {
    my $Int := $*W.find_symbol(['Int']);
    my $power := nqp::box_i(0, $Int);
    for $<dig> {
        $power := nqp::add_I(
           nqp::mul_I($power, nqp::box_i(10, $Int), $Int),
           nqp::box_i(nqp::index("⁰¹²³⁴⁵⁶⁷⁸⁹", $_), $Int),
           $Int);
    }

    $power := nqp::neg_I($power, $Int) 
        if $<sign> eq '⁻' || $<sign> eq '¯';
    make QAST::Op.new(:op<call>, :name('&postfix:<ⁿ>'), 
                      $*W.add_numeric_constant($/, 'Int', $power));
}

As you can see here, it scans the digits and updates the $power variable by adding the value at the next decimal position (it is selected in the code above).

The available characters are listed in a string, and to get its value, the offset in the string is used. The $<dig> match contains a digit, you can see it in the Grammar:

<dig=[⁰¹²³⁴⁵⁶⁷⁸⁹]>+

 

🔬71. Implementing Int.sleep() in Perl 6

Hello! Yesterday, I was giving my Perl 6 Intro course at the German Perl Workshop in Gummersbash. It was a great pleasure to prepare and run this one-day course, and, while it was difficult to cover everything, we touched all main aspects of the Perl 6 language: from variables to regexes and parallel computing. Of course, it was only a top-level overview, and there was not enough time to make all the exercises. You can do them at home, here’s the Perl 6 Intro – Exercises PDF file.

Among the rest, we tried to implement the sleep method for integers. The rationale behind that is that it is possible to say:

> 10.rand
9.9456903794802

But not:

> 10.sleep
No such method 'sleep' for invocant of type 'Int'
  in block <unit> at <unknown file> line 1

OK, so let’s first implement the simplest form of sleep for Ints only. Go to src/core/Int.pm6 and add the following:

my class Int does Real {

    method sleep() {
        nqp::sleep($!value);
    }

Here’s a photo from the screen:

29695497_10156162162038326_7927919948344098147_n

There is no declaration of the $!value attribute in this file, but we know that it can be found somewhere in Perl6/Metamodel/BOOTSTRAP.nqp:

# class Int is Cool {
# has bigint $!value is box_target;
Int.HOW.add_parent(Int, Cool);
Int.HOW.add_attribute(Int,
    BOOTSTRAPATTR.new(:name<$!value>, :type(bigint), 
                      :box_target(1), :package(Int)));
Int.HOW.set_boolification_mode(Int, 6);
Int.HOW.publish_boolification_spec(Int);
Int.HOW.compose_repr(Int);

Compile and run. The desired code works now:

> 3.sleep
# sleeping 3 seconds
>

What can be changed here? The first idea is to allow non-integer numbers as the delay duration. As Int does the Real role, just move the method to src/core/Real.pm and get the value using the Num method instead of reading $!value directly (there is no such attribute in the Real role):

my role Real does Numeric {

    method sleep() { 
        nqp::sleep(self.Num);
    }

Now it also works with rationals and floating-point numbers:

> 2.sleep
2

> 3.14.sleep
3.14

> pi.sleep
3.14159265358979

Before wrapping it up, let us take a look at the body of the sleep subroutine. It is defined in src/core/Date.pm6:

proto sub sleep(|) {*}
multi sub sleep(--> Nil) { sleep(*) }
multi sub sleep($seconds --> Nil) {
    # 1e9 seconds is a large enough value that still makes VMs sleep
    # larger values cause nqp::sleep() to exit immediatelly (esp. on 32-bit)
    if nqp::istype($seconds,Whatever) || $seconds == Inf {
        nqp::sleep(1e9) while True;
    }
    elsif $seconds > 1e9 {
        nqp::sleep($_) for gather {
            1e9.take xx ($seconds / 1e9);
            take $seconds - 1e9 * ($seconds / 1e9).Int;
        }
    }
    elsif $seconds > 0e0 {
        nqp::sleep($seconds.Num);
    }
}

The code is very clear and does not need any comments.

And maybe just to see why our modified Rakudo printed the time after sleep in the tests above, let’s refer to the documentation of NQP to see that its sleep function’s return value is the number of seconds:

## sleep
* `sleep(num $seconds --> num)`

Sleep for the given number of seconds (no guarantee is made
how exact the time sleeping is spent.)
Returns the passed in number.

 

🔬70. Examining the enum type in Perl 6

In Perl 6, you can create enumerations like this:

enum colour <red orange yellow green blue violet>;

Having this said, you can use the new name as a type name and create variables of that type:

my colour $c;

$c = green;
say $c;     # green
say $c.Int; # 3

As you would rightly expect, the type of the variable is very predictable:

say $c.^name; # colour

Now, try to find the class implementation in Rakudo sources. Surprisingly, there is no file src/core/Enum.pm, but instead, there is src/core/Enumeration.pm. Looking at that file, you cannot say how our program works. Let us dig a bit.

In Grammar (src/Perl6/Grammar.nqp), you can find the following piece:

proto token type_declarator { <...> }

token type_declarator:sym<enum> {
    . . .
}

So, the enum is not a name of the data type but a predefined keyword, one of a few that exist for type declarations (together with subset and constant).

The token starts with consuming the keyword and making some preparations, which are not very interesting for us at the moment:

<sym><.kok>
:my $*IN_DECL := 'enum';
:my $*DOC := $*DECLARATOR_DOCS;
{ $*DECLARATOR_DOCS := '' }
:my $*POD_BLOCK;
:my $*DECLARAND;
{
    my $line_no := HLL::Compiler.lineof(self.orig(), self.from(), :cache(1));
    if $*PRECEDING_DECL_LINE < $line_no {
        $*PRECEDING_DECL_LINE := $line_no;
        $*PRECEDING_DECL := Mu; # actual declarand comes later, in Actions::type_declarator:sym<enum>
    }
}
<.attach_leading_docs>

Then, we expect either a name of the new type or a variable or nothing(?):

[
| <longname>
    {
     . . .
    }
| <variable>
| <?>
]

The variable part is not yet implemented:

> enum $x <a b c>
===SORRY!=== Error while compiling:
Variable case of enums not yet implemented. Sorry.
at line 2

Our test program falls to the first branch:

<longname>
  {
      my $longname := $*W.dissect_longname($<longname>);
      my @name := $longname.type_name_parts('enum name', :decl(1));
      if $*W.already_declared($*SCOPE, self.package, $*W.cur_lexpad(), @name) {
          $*W.throw($/, ['X', 'Redeclaration'],
                    symbol => $longname.name(),
          );
      }
  }

For example, if you declare enum colour, then the $longname.name() returns colour colour. Thus, we extracted it. (Also notice how redeclaration is handled.)

Finally, here is the rest of the token body:

{ $*IN_DECL := ''; }
<.ws>
<trait>*
:my %*MYSTERY;
[ <?[<(«]> <term> <.ws> || <.panic: 'An enum must supply an expression using <>, «», or ()'> ]
<.explain_mystery> <.cry_sorrows>

Indeed, we need to explain the mystery here. So, there’s room for optional traits, fine:

<trait>*

There’s another construct that should match to avoid panic messages:

<?[<(«]> <term> <.ws>

Don’t be confused by the different number of opening and closing angle brackets here. The first part is a forward assertion with a character class:

<?  [<(«]  >

It looks if there is one of the <, (, or « opening bracket at this position. The panic message is displayed if it is not found there.

Our next expected guest is a term. Obviously, the whole part <red orange . . . violet> matches with it. Not that bad; what we need to do now is to understand what happens next.

🦋 69. Setting timeouts in Perl 6

In Perl 5, I used to set timeouts using signals (or, at least, that was an easy and predictable way). In Perl 6, you can use promises. Let us see how to do that.

To imitate a long-running task, create an infinite loop that prints its state now and then. Here it is:

for 1 .. * {
    .say if $_ %% 100_000;
}

As soon as the loop gets control, it will never quit. Our task is to stop the program in a couple of seconds, so the timer should be set before the loop:

Promise.in(2).then({
    exit;
});

for 1 .. * {
    .say if $_ %% 100_000;
}

Here, the Promise.in method creates a promise that is automatically kept after the given number of seconds. On top of that promise, using then, we add another promise, whose code will be run after the timeout. The only statement in the body here is exit that stops the main program.

Run the program to see how it works:

$ time perl6 timeout.pl
100000
200000
300000
. . .
3700000
3800000
3900000

real 0m2.196s
user 0m2.120s
sys 0m0.068s

The program counts up to about four millions on my computer and quits in two seconds. That is exactly the behaviour we needed.

For comparison, here is the program in Perl 5:

use v5.10;

alarm 2;
$SIG{ALRM} = sub {
    exit;
};

for (my $c = 1; ; $c++) {
    say $c unless $c % 1_000_000;
}

(It manages to count up to 40 million, but that’s another story.)