🔬36. Rakudo 2018.01

A new release of Rakudo was just announced. Most of the changes increase Perl 6 performance this time. Let us briefly look at some of them.

I am happy to tell that my blog initiated at least two of the changes.

Removed UInt64 (not to be confused with uint64) [cf154355]

We’ve seen this class in the post about native integers. The UInt64 type remained in the codebase for a long time while it was not actually used. The uint type, though, is still to-be-used as the type of the denominator in Rats:

# XXX: should be Rational[Int, uint]
my class Rat is Cool does Rational[Int, Int] {

As we saw, the DateTime constructor used the in-range method, which was replaced with faster explicit tests:

- (1..12).in-range($month,'Month'); - (1 .. self.DAYS-IN-MONTH($year,$month)).in-range($day,'Day');
- (0..23).in-range($hour,'Hour'); - (0..59).in-range($minute,'Minute');

+ 1 <= $month <= 12 + || X::OutOfRange.new(:what<Month>,:got($month),:range<1..12>).throw;
+ 1 <= $day <= self.DAYS-IN-MONTH($year,$month) + || X::OutOfRange.new( + :what<Day>, + :got($day),
+         :range("1..{self.DAYS-IN-MONTH($year,$month)}")
+     ).throw;
+ 0 <= $hour <= 23 + || X::OutOfRange.new(:what<Hour>,:got($hour),:range<0..23>).throw;
+ 0 <= $minute <= 59 + || X::OutOfRange.new(:what<Minute>,:got($minute),:range<0..59>).throw;



Creating Rats is an interesting procedure, which I am going to blog about in the future. For now, let me show the changes from this commit:

sub DON'T_DIVIDE_NUMBERS(Int:D \nu, Int:D \de, $t1,$t2) {

-     my $r; - if nqp::istype($t1, FatRat) || nqp::istype($t2, FatRat) { -$r := nqp::create(FatRat);
-         nqp::bindattr($r, FatRat, '$!numerator', nqp::decont(nu));
-         nqp::bindattr($r, FatRat, '$!denominator', nqp::decont(de));
-     } else {
-         $r := nqp::create(Rat); - nqp::bindattr($r, Rat, '$!numerator', nqp::decont(nu)); - nqp::bindattr($r, Rat, '$!denominator', nqp::decont(de)); - } -$r;

+     nqp::istype($t1, FatRat) || nqp::istype($t2, FatRat)
+         ?? nqp::p6bindattrinvres(
+                nqp::p6bindattrinvres(
+                    nqp::create(FatRat),
+                    FatRat, '$!numerator', nqp::decont(nu)), + FatRat, '$!denominator', nqp::decont(de))
+         !! nqp::p6bindattrinvres(
+                nqp::p6bindattrinvres(
+                    nqp::create(Rat),
+                    Rat, '$!numerator', nqp::decont(nu)), + Rat, '$!denominator', nqp::decont(de))



This is a routine that is a part of creating a Rat value from two integers. A Rat value internally contains two attributes, the numerator and the denominator. They were bound via the nqp::bindattr method with the help of some temporary variable. Now the Rakudo’s nqp::p6bindattrinvres method is used directly. This method is equivalent to the following code (see docs/ops.markdown in the Rakudo directory):

{
bindattr($obj,$type, $attr-name,$value);
$obj; } Made use of faster typechecks (7.5x faster) [4c9b84f8][8f71b0e0][10cd405f] The key idea of this change is to replace the Perl 6 type checks with NQP ones, all changes are in src/Perl6/Actions.nqp, for example: - if$past.isa(QAST::Var) {
+ if nqp::istype($past, QAST::Var) { - if$elem ~~ QAST::Op
+ if nqp::istype($elem, QAST::Op) As a useful exercise, you can trace back the behaviour of both .isa and ~~ in the code and see why it could slow down the check. Made operator chains up to 2.4x faster [b77d8756] The change was made in src/Perl6/Optimizer.nqp, and we are not going to read it here, but I wanted to mention this change because it is relevant to a small but very handy feature of Perl 6, chain comparisons such as 1 <$x < 2. It is claimed that now it works almost as fast as 1 < $x &&$x < 2.

This is an interesting change in the code that, basically, avoids using a loop for adding up two values:

- nqp::stmts(
-   (my $list :=$!reified),
-   (my $sum = nqp::ifnull(nqp::atpos($list,0),0)),
-   (my int $i), - nqp::while( - nqp::islt_i($i = nqp::add_i($i,1),$elems),
-     ($sum =$sum + nqp::ifnull(nqp::atpos($list,$i),0))

+ nqp::if(
+   nqp::isgt_i($elems,2), + nqp::stmts( + (my$list := $!reified), + (my$sum = nqp::ifnull(nqp::atpos($list,0),0)), + (my int$i),
+     nqp::while(
+       nqp::islt_i($i = nqp::add_i($i,1),$elems), + ($sum = $sum + nqp::ifnull(nqp::atpos($list,$i),0)) + ), +$sum

A lot of NQP code here in src/core/List.pm, but you can understand it if I tell you that nqp::stmts makes a sequence of statements a single statement. Thus, the nqp::isgt_i check has two branches: for arrays that either have one or two, or arrays with more elements.

There are more interesting changes but most of them require deeper understanding of Rakudo.