Day 11 — All the Stars of Perl 6, or * ** *

Today’s blog post in this year’s Perl 6 Advent Calendar is full of snowflakes. We’ll go through the constructs that employ the * character. In Perl 6, you may call it a star (or asterisk if you prefer) or a whatever, depending on the context.

Perl 6 is not a cryptic programming language; its syntax is in many aspects much more consistent than that of Perl 5. On the other side, some areas require spending time to start feeling confident in the syntax.

Let’s go through different usages of *, starting with the most simple, aiming to understand the most brain-breaking ones such as * ** *.

The first couple of usages is simple and does not require many comments:

1. Multiplication

A single star is used for multiplication. Strictly speaking, this is an infix operator infix:, whose return value is Numeric.

say 20 * 18; # 360

2. Power

The double star ** is the exponentiation operator. Again, this is an infix: that returns the Numeric result, calculating the power for the given two values.

say pi ** e; # 22.4591577183611

* * *

The same two tokens, * or **, are also used in regexes, where they mean different things. One of the features of Perl 6 is that it can easily switch between different languages inside itself. Both regexes and grammars are examples of such inner languages, where the same symbols can mean different things from what they mean in Perl 6 itself (if they have any meaning at all there).

3. Zero or more repetitions

The * quantifier. This syntax item works similarly to its behaviour in Perl 5: allows zero or more repetitions of the atom.

my $weather = '*****';
my $snow = $weather ~~ / ('*'*) /;
say 'Snow level is ' ~ $snow.chars; # Snow level is 5

Of course, we also see here another usage of the same character, the '*' literal.

4. Min to max repetitions

The double ** is a part of another quantifier that specifies the minimum and the maximum number of repetitions:

my $operator = '..';
say "'$operator' is a valid Perl 6 operator"
    if $operator ~~ /^ '.' ** 1..3 $/;

In this example, it is expected that the dot is repeated one, two, or three times; not less and not more.

Let’s look a bit ahead, and use a star in the role (role as in theatre, not in Perl 6’s object-oriented programming) of the Whatever symbol:

my $phrase = 'I love you......';
say 'You are so uncertain...'
    if $phrase ~~ / '.' ** 4..* /;

The second end of the range is open, and the regex accepts all the phrases with more than four dots in it.

5. Slurpy arguments

A star before an array argument in a sub’s signature means a slurpy argument—the one that consumes separate scalar parameters into a single array.

list-gifts('chocolade', 'ipad', 'camelia', 'perl6');

sub list-gifts(*@items) {
    say 'Look at my gifts this year:';
    .say for @items;
}

Hashes also allow celebrating slurpy parameters:

dump(alpha => 'a', beta => 'b'); # Prints:
                                 # alpha = a
                                 # beta = b

sub dump(*%data) {
    for %data.kv {say "$^a = $^b"}
}

Notice that unlike Perl 5, the code does not compile if you omit the star in the function signature, as Perl 6 expects exactly what is announced:

Too few positionals passed; expected 1 argument but got 0

6. Slurpy-slurpy

The **@ is also working but notice the difference when you pass arrays or lists.

With a single star:

my @a = < chocolade ipad >;
my @b = < camelia perl6 >;

all-together(@a, @b);
all-together(['chocolade', 'ipad'], ['camelia', 'perl6']);
all-together(< chocolade ipad >, < camelia perl6 >);

sub all-together(*@items) {
    .say for @items;
}

Currently, each gift is printed on a separate line regardless the way the argument list was passed.

With a double star:

keep-groupped(@a, @b);
keep-groupped(['chocolade', 'ipad'], ['camelia', 'perl6']);
keep-groupped(< chocolade ipad >, < camelia perl6 >);

sub keep-groupped(**@items) {
    .say for @items;
}

This time, the @items array gets two elements only, reflecting the structural types of the arguments:

[chocolade ipad]
[camelia perl6]

or

(chocolade ipad)
(camelia perl6)

7. Dynamic scope

The * twigil, which introduces dynamic scope. It is easy to confuse the dynamic variables with global variables but examine the following code.

sub happy-new-year() {
    "Happy new $*year year!"
}

my $*year = 2018;
say happy-new-year();

If you omit the star, the code cannot be run:

Variable '$year' is not declared

The only way to make it correct is to move the definition of $year above the function definition. With the dynamic variable $*year, the place where the function is called defines the result. The $*year variable is not visible in the outer scope of the sub, but it is quite visible in the dynamic scope.

For the dynamic variable, it is not important whether you assign a new value to an existing variable or create a new one:

sub happy-new-year() {
    "Happy new $*year year!"
}

my $*year = 2018;
say happy-new-year();

{
    $*year = 2019;        # New value
    say happy-new-year(); # 2019
}

{
    my $*year = 2020;     # New variable
    say happy-new-year(); # 2020
}

8. Compiler variables

A number of dynamic pseudo-constants come with Perl 6, for example:

say $*PERL;      # Perl 6 (6.c)
say @*ARGS;      # Prints command-line arguments
say %*ENV<HOME>; # Prints home directory

9. All methods

The .* postfix pseudo-operator calls all the methods with the given name, which can be found for the given object, and returns a list of results. In the trivial case you get a scholastically absurd code:

6.*perl.*say; # (6 Int.new)

The code with stars is a bit different from doing it simple and clear:

pi.perl.say; # 3.14159265358979e0 (notice the scientific
             # format, unlike pi.say)

The real power of the .* postfix comes with inheritance. It helps to reveal the truth sometimes:

class Present {
    method giver() {
        'parents'
    }
}

class ChristmasPresent is Present {
    method giver() {
        'Santa Claus'
    }
}

my ChristmasPresent $present;

$present.giver.say;             # Santa Claus
$present.*giver.join(', ').say; # Santa Claus, parents

Just a star but what a difference!

* * *

Now, to the most mysterious part of the star corner of Perl 6. The next two concepts, the Whatever and the WhateverCode classes, are easy to mix up with each other. Let’s try to do it right.

10. Whatever

A single * can represent Whatever. Whatever in Perl 6 is a predefined class, which introduces some prescribed behaviour in a few useful cases.

For example, in ranges and sequences, the final * means infinity. We’ve seen an example today already. Here is another one:

.say for 1 .. *;

This one-liner has a really high energy conversion efficiency as it generates an infinite list of increasing integers. Press Ctrl+C when you are ready to move on.

The range 1 .. * is the same as 1 .. Inf. You can clearly see that if you go to the Rakudo Perl 6 sources and find the following definitions in the implementation of the Range class in the src/core/Range.pm file:

multi method new(Whatever \min,Whatever \max,:$excludes-min,:$excludes-max){
    nqp::create(self)!SET-SELF(-Inf,Inf,$excludes-min,$excludes-max,1);
}
multi method new(Whatever \min, \max, :$excludes-min, :$excludes-max) {
    nqp::create(self)!SET-SELF(-Inf,max,$excludes-min,$excludes-max,1);
}
multi method new(\min, Whatever \max, :$excludes-min, :$excludes-max) {
    nqp::create(self)!SET-SELF(min,Inf,$excludes-min,$excludes-max,1);
}

The three multi constructors describe the three cases: * .. *, * .. $n and $n .. *, which are immediately translated to -Inf .. Inf, -Inf .. $n and $n .. Inf.

As a side Christmas tale, here’s a tiny excursus showing that * is not just an Inf. There were two commits to src/core/Whatever.pm:

First, on 16 September 2015, “Make Whatever.new == Inf True:”

  my class Whatever {
      multi method ACCEPTS(Whatever:D: $topic) { True }
      multi method perl(Whatever:D:) { '*' }
+     multi method Numeric(Whatever:D:) { Inf }
  }

In a few weeks, on 23 October 2015, “* no longer defaults to Inf,” This is to protect extensibility of * to other dwimmy situations:

  my class Whatever {
      multi method ACCEPTS(Whatever:D: $topic) { True }
      multi method perl(Whatever:D:) { '*' }
-     multi method Numeric(Whatever:D:) { Inf }
  }

Returning to our more practical problems, let’s create our own class that makes use of the whatever symbol *. Here is a simple example of a class with a multi-method taking either an Int value or a Whatever.

class N {
    multi method display(Int $n) {
        say $n;
    }

    multi method display(Whatever) {
        say 2000 + 100.rand.Int;
    }
}

In the first case, the method simply prints the value. The second method prints a random number between 2000 and 2100 instead. As the only argument of the second method is Whatever, no variable is needed in the signature.

Here is how you use the class:

my $n = N.new;
$n.display(2018);
$n.display(*);

The first call echoes its argument, while the second one prints something random.

The Whatever symbol can be held as a bare Whatever. Say, you create an echo function and pass the * to it:

sub echo($x) {
    say $x;
}

echo(2018); # 2018
echo(*);    # *

This time, no magic happens, the program prints a star.

And now we are at a point where a tiny thing changes a lot.

11. WhateverCode

Finally, it’s time to talk about WhateverCode.

Take an array and print the last element of it. If you do it in the Perl 5 style, you’d type something like @a[-1]. In Perl 6, that generates an error:

Unsupported use of a negative -1 subscript
to index from the end; in Perl 6 please
use a function such as *-1

The compiler suggests to use a function such as *-1. Is it a function? Yes, more precisely, a WhateverCode block:

say (*-1).WHAT; # (WhateverCode)

Now, print the second half of an array:

my @a = < one two three four five six >;
say @a[3..*]; # (four five six)

An array is indexed with the range 3..*. The Whatever star as the right end of the range means to take all the rest from the array. The type of 3..* is a Range:

say (3..*).WHAT; # (Range)

Finally, take one element less. We’ve already seen that to specify the last element a function such as *-1 must be used. The same can be done at the right end of the range:

say @a[3 .. *-2]; # (four five)

At this point, the so-called Whatever-currying happens and a Range becomes a WhateverCode:

say (3 .. *-2).WHAT; # (WhateverCode)

WhateverCode is a built-in Perl 6 class name; it can easily be used for method dispatching. Let’s update the code from the previous section and add a method variant that expects a WhateverCode argument:

class N {
    multi method display(Int $n) {
        say $n;
    }

    multi method display(Whatever) {
        say 2000 + 100.rand.Int;
    }

    multi method display(WhateverCode $code) {
        say $code(2000 + 100.rand.Int);
    }
}

Now, the star in the argument list falls into either display(Whatever) or display(WhateverCode):

N.display(2018);     # display(Int $n)

N.display(*);        # display(Whatever)

N.display(* / 2);    # display(WhateverCode $code)
N.display(* - 1000); # display(WhateverCode $code)

Once again, look at the signature of the display method:

multi method display(WhateverCode $code)

The $code argument is used as a function reference inside the method:

say $code(2000 + 100.rand.Int);

The function takes an argument but where is it going to? Or, in other words, what and where is the function body? We called the method as N.display(* / 2) or N.display(* - 1000). The answer is that both * / 2 and * - 1000 are functions! Remember the compiler’s hint about using a function such as *-1?

The star here becomes the first function argument, and thus * / 2 is equivalent to {$^a / 2}, while * - 1000 is equivalent to {$^a - 1000}.

Does it mean that $^b can be used next to $^a? Sure! Make the WhateverCode block accept two arguments. How do you indicate the second of them? Not a surprise, with another star! Let us add the fourth variant of the display method to our class:

multi method display(WhateverCode $code 
                     where {$code.arity == 2}) {
    say $code(2000, 100.rand.Int);
}

Here, the where block is used to narrow the dispatching down to select only those WhateverCode blocks that have two arguments. Having this done, two snowflakes are allowed in the method call:

N.display( * + * );
N.display( * - * );

The calls define the function $code that is used to calculate the result. So, the actual operation behind the N.display( * + * ) is the following: 2000 + 100.rand.Int.

Need more snow? Add more stars:

N.display( * * * );
N.display( * ** * );

Similarly, the actual calculations inside are:

2000 * 100.rand.Int

and

2000 ** 100.rand.Int

Congratulations! You can now parse the * ** * construct as effortlessly as the compiler does it.

Homework

Perl 6 gave us so many Christmas gifts so far. Let’s make an exercise in return and answer the question: What does each star mean in the following code?

my @n = 
    ((0, 1, * + * ... *).grep: *.is-prime).map: * * * * *;
.say for @n[^5];

D’oh. I suggest we start transforming the code to get rid of all the stars and to use different syntax.

The * after the sequence operator ... means to generate the sequence infinitely, so replace it with Inf:

((0, 1, * + * ... Inf).grep: *.is-prime).map: * * * * *

The two stars * + * in the generator function can be replafced with a lambda function with two explicit arguments:

((0, 1, -> $x, $y {$x + $y} ... Inf).grep: 
    *.is-prime).map: * * * * *

Now, a simple syntax alternation. Replace the .grep: with a method call with parentheses. Its argument *.is-prime becomes a codeblock, and the star is replaced with the default variable $_. Notice that no curly braces were needed while the code was using a *:

(0, 1, -> $x, $y {$x + $y} ... Inf).grep({
    $_.is-prime
}).map: * * * * *

Finally, the same trick for .map: but this time there are three arguments for this method, thus, you can write {$^a * $^b * $^c} instead of * * * * *, and here’s the new variant of the complete program:

my @n = (0, 1, -> $x, $y {$x + $y} ... Inf).grep({
        $_.is-prime
    }).map({
        $^a * $^b * $^c
    });
.say for @n[^5];

Now it is obvious that the code prints five products of the groups of three prime Fibonacci numbers.

Additional assignments

In textbooks, the most challenging tasks are marked with a *. Here are a couple of them for your to solve yourself.

  1. What is the difference between chdir('/') and &*chdir('/') in Perl 6?
  2. Explain the following Perl 6 code and modify it to demonstrate its advantages: .say for 1...**.

❄ ❄ ❄

That’s all for today. I hope that you enjoyed the power and expressiveness of Perl 6. Today, we talked about a single ASCII character only. Imagine how vast Perl 6’s Universe is if you take into account that the language offers the best Unicode support among today’s programming languages.

Enjoy Perl 6 today and spread the word! Stay tuned to the Perl 6 Advent Calendar; more articles are waiting for your attention, the next coming already tomorrow.

Andrew Shitov

Day 10 – Wrapping Rats

Going down chimneys is a dangerous business.

Chimneys can be narrow, high, and sometimes not well constructed to begin with.

This year, Santa wants to be prepared. Therefore, he is combining a chimney inspection with the delivery of presents.

A chimney inspection involves ensuring that every layer of bricks is at the correct height; i.e. that the layers of mortar are consistent, and that the bricks are also a consistent height.

For instance, for bricks that are 2¼” high, and mortar that is ⅜” thick, the sequence of measurements should look like this:

                       🎅 
                      ─██─
                       ||
 layer                                      total
       ░░░░░░░░░░ ░░░░░░░░░░░░░░░ ░░░░░░░░░░
  2¼   ░░░░░░░░░░ ░░░░░░░░░░░░░░░ ░░░░░░░░░░
       ░░░░░░░░░░ ░░░░░░░░░░░░░░░ ░░░░░░░░░░
   ⅜                                        ‾‾???
       ░░░░░ ░░░░░░░░░░░░░ ░░░░░░░░░░░░ ░░░░
  2¼   ░░░░░ ░░░░░░░░░░░░░ ░░░░░░░░░░░░ ░░░░
       ░░░░░ ░░░░░░░░░░░░░ ░░░░░░░░░░░░ ░░░░
   ⅜                                        ‾‾5⅝
       ░░░░░░░░░░ ░░░░░░░░░░░░░ ░░░░░░░░░░░░
  2¼   ░░░░░░░░░░ ░░░░░░░░░░░░░ ░░░░░░░░░░░░ 
       ░░░░░░░░░░ ░░░░░░░░░░░░░ ░░░░░░░░░░░░
   ⅜                                        ‾‾3
       ░░░░░░ ░░░░░░░░░░░░░ ░░░░░░░░░░░░ ░░░
  2¼   ░░░░░░ ░░░░░░░░░░░░░ ░░░░░░░░░░░░ ░░░ 
       ░░░░░░ ░░░░░░░░░░░░░ ░░░░░░░░░░░░ ░░░
   ⅜   _____________________________________‾‾⅜ 

The plan is for the Elves to do the dangerous descent to the bottom, tape measure in hand, and then come back up, ensuring that the top of each brick layer is at precisely the correct place on the tape measure.

One particular Elf, named Elvis, has taken it upon himself to write a program to help out with the task of computing this sequence of heights.

Being lazy, Elvis did not even want to add any of the fractions above, and wanted the program to do all the work. He also did not want to exert the mental effort required to figure out the formula for the height of each layer. Luckily, he was using Perl 6, which properly turns unicode fractions into rational numbers (type Rat), and also has a sequence operator (...) which figures out arithmetic sequences based on the first few terms.

So, Elvis’ first cut at the program looked like this:

my @heights = 0, ⅜, 3, 5+⅝ ... *;

say @heights[^10].join(', ')

This gave him the first 10 heights that he needed:

0, 0.375, 3, 5.625, 8.25, 10.875, 13.5, 16.125, 18.75, 21.375

While this was correct, it was hard to use. The tape measure had fractions of an inch, not decimals. The output Elvis really wanted was fractions.

Fortunately, he knew that using join turned the Rats into strings, Turning a Rat into a Str is done by calling the Str method of the Rat class. So, by modifying the behavior of Rat.Str, he figured he could make the output prettier.

The way he decided to do this was to wrap the Str method (aka using the decorator pattern), like so:

Rat.^find_method('Str').wrap:
  sub ($r) {
    my $whole = $r.Int || "";
    my $frac = $r - $whole;
    return "$whole" unless $frac > 0;
    return "$whole" ~ <⅛ ¼ ⅜ ½ ⅝ ¾ ⅞>[$frac * 8 - 1];
  }

In other words, when stringifying a Rat, return the whole portion unless there is a fractional portion. Then treat the fractional portion as the number of eighths, and use that as an index into an array to look up the right unicode fraction.

He combined that with his first program to get this sequence of heights:

0, ⅜, 3, 5⅝, 8¼, 10⅞, 13½, 16⅛, 18¾, 21⅜

“Hooray!” he thought. “Exactly what I need.”

Santa took a look at the program and said “Elvis, this is clever, but not quite enough. While most brick dimensions are multiples of ⅛ , that might not be true of mortar levels. Can you make your program handle those cases, too?”

“Sure” said Elvis with a wry smile. And he added this line into his wrapper function:

return "$whole {$frac.numerator}⁄{$frac.denominator}"
   unless $frac %% ⅛;

using the “is divisible by” operator (%%), to ensure that the fraction was evenly divisible into eighths, and if not to just print the numerator and denominator explicitly. Then for mortar that was ⅕” thick, the sequence:

my @heights = 0, ⅕,
                 ⅕ + 2+¼ + ⅕,
                 ⅕ + 2+¼ + ⅕
                   + 2+¼ + ⅕ ... *;
say @heights[^10].join(', ');
0,  1⁄5, 2 13⁄20, 5 1⁄10, 7 11⁄20, 10, 12 9⁄20, 14 9⁄10, 17 7⁄20, 19 4⁄5

“Actually”, Santa said, “now that I look at it, maybe this isn’t useful — the tape measure only has sixteenths of an inch, so it would be better to round to the nearest sixteenth of an inch.”

tape-measure

Elvis added a call to round to end up with:


Rat.^find_method('Str').wrap:
  sub ($r) {
        my $whole = $r.Int || '';
        my $frac = $r - $whole;
        return "$whole" unless $frac > 0;
        my $rounded = ($frac * 16).round/16;
        return "$whole" ~ <⅛ ¼ ⅜ ½ ⅝ ¾ ⅞>[$frac * 8 - 1] if $rounded %% ⅛;
        return "$whole {$rounded.numerator}⁄{$rounded.denominator}";
  }

which gave him

0,  3⁄16, 2⅝, 5⅛, 7 9⁄16, 10, 12 7⁄16, 14⅞, 17¼, 19 13⁄16

He showed his program to Elivra the Elf who said, “What a coincidence, I wrote a program that is almost exactly the same! Except, I also wanted to know where the bottoms of the layers of bricks are. I couldn’t use a sequence operator for this, since it isn’t an arithmetic progression, but I could use a lazy gather and an anonymous stateful variable! Like this:


my \brick = 2 + ¼;
my \mortar = ⅜;
my @heights = lazy gather {
    take 0;
    loop { take $ += $_ for mortar, brick }
}

Elvira’s program produced:

0, ⅜, 2⅝, 3, 5¼, 5⅝, 7⅞, 8¼, 10½, 10⅞

i.e. both the tops and the bottoms of the layers of bricks:

                     \ 🎅 /
                       ██
                       ||
 layer                                      total
       ░░░░░░░░░░ ░░░░░░░░░░░░░░░ ░░░░░░░░░░
  2¼   ░░░░░░░░░░ ░░░░░░░░░░░░░░░ ░░░░░░░░░░
       ░░░░░░░░░░ ░░░░░░░░░░░░░░░ ░░░░░░░░░░
   ⅜                                        ‾‾8¼
       ░░░░░ ░░░░░░░░░░░░░ ░░░░░░░░░░░░ ░░░░‾‾7⅞
  2¼   ░░░░░ ░░░░░░░░░░░░░ ░░░░░░░░░░░░ ░░░░
       ░░░░░ ░░░░░░░░░░░░░ ░░░░░░░░░░░░ ░░░░
   ⅜                                        ‾‾5⅝
       ░░░░░░░░░░ ░░░░░░░░░░░░░ ░░░░░░░░░░░░‾‾5¼
  2¼   ░░░░░░░░░░ ░░░░░░░░░░░░░ ░░░░░░░░░░░░ 
       ░░░░░░░░░░ ░░░░░░░░░░░░░ ░░░░░░░░░░░░
   ⅜                                        ‾‾3
       ░░░░░░ ░░░░░░░░░░░░░ ░░░░░░░░░░░░ ░░░‾‾2⅝
  2¼   ░░░░░░ ░░░░░░░░░░░░░ ░░░░░░░░░░░░ ░░░ 
       ░░░░░░ ░░░░░░░░░░░░░ ░░░░░░░░░░░░ ░░░
   ⅜   _____________________________________‾‾⅜
                                            ‾‾0

With their programs in hand, the Elves checked out the chimneys and Santa made it through another holiday season without any injuries.

Day 9 – HTTP and Web Sockets with Cro

It’s not only Christmas time when gifts are given. This summer at the Swiss Perl Workshop – beautifully situated up in the Alps – I had the pleasure of revealing Cro. Cro is a set of libraries for building services in Perl 6, together with a little development tooling to stub, run, and trace services. Cro is intially focused on building services with HTTP (including HTTP/2.0) and web sockets, but early support for ZeroMQ is available, and a range of other options are planned for the future.

Reactive pipelines

Cro follows the Perl design principle of making the easy things easy, and the hard things possible. Much like Git, Cro can be thought of as having porcelain (making the easy things easy) and plumbing (making the hard things possible). The plumbing level consists of components that are composed to form pipelines. The components come in different shapes, such as sources, transforms, and sinks. Here’s a transform that turns a HTTP request into a HTTP response:

use Cro;
use Cro::HTTP::Request;
use Cro::HTTP::Response;
class MuskoxApp does Cro::Transform {
method consumes() { Cro::HTTP::Request }
method produces() { Cro::HTTP::Response }
method transformer(Supply $pipeline --> Supply) {
supply whenever $pipeline -> $request {
given Cro::HTTP::Response.new(:$request, :200status) {
.append-header: "Content-type", "text/html";
.set-body: "Muskox Rocks!\n".encode('ascii');
.emit;
}
}
}
}

Now, let’s compose it with a TCP listener, a HTTP request parser, and a HTTP response serializer:

use Cro::TCP;
use Cro::HTTP::RequestParser;
use Cro::HTTP::ResponseSerializer;
my $server = Cro.compose:
Cro::TCP::Listener.new(:port(4242)),
Cro::HTTP::RequestParser.new,
MuskoxApp,
Cro::HTTP::ResponseSerializer;

That gives back a Cro::Service, which we can now start, and stop upon Ctrl+C:

$server.start;
react whenever signal(SIGINT) {
$server.stop;
exit;
}

Run it. Then curl it.

$ curl http://localhost:4242/
Muskox Rocks!

Not bad. But what if we wanted a HTTPS server? Provided we’ve got key and certificate files handy, that’s just a case of replacing the TCP listener with a TLS listener:

use Cro::TLS;
my $server = Cro.compose:
Cro::TLS::Listener.new(
:port(4242),
:certificate-file('certs-and-keys/server-crt.pem'),
:private-key-file('certs-and-keys/server-key.pem')
),
Cro::HTTP::RequestParser.new,
MuskoxApp,
Cro::HTTP::ResponseSerializer;

Run it. Then curl -k it.

$ curl -k https://localhost:4242/
Muskox Rocks!

And middleware? That’s just another component to compose into the pipeline. Or, seen another way, with Cro everything is middleware. Even the request parser or response serializer can be easily replaced, should the need arise (which sounds like an odd thing to need, but that’s effectively what implementing FastCGI would involve).

So, that’s how Cro is plumbed. It also requires an amount of boilerplate to work at this level. Bring in the porcelain!

HTTP server, the easy way

The Cro::HTTP::Server class gets rid of the boilerplate of building the HTTP processing pipeline. The example from earlier becomes just:

use Cro;
use Cro::HTTP::Server;
class MuskoxApp does Cro::Transform {
method consumes() { Cro::HTTP::Request }
method produces() { Cro::HTTP::Response }
method transformer(Supply $pipeline --> Supply) {
supply whenever $pipeline -> $request {
given Cro::HTTP::Response.new(:$request, :200status) {
.append-header: "Content-type", "text/html";
.set-body: "Muskox Rocks!\n".encode('ascii');
.emit;
}
}
}
}
my $server = Cro::HTTP::Server.new: :port(4242), :application(MuskoxApp);
$server.start;
react whenever signal(SIGINT) {
$server.stop;
exit;
}

There’s no magic here; it really is just a more convenient way to compose a pipeline. And while that’s only so much of a saving for HTTP/1.*, a HTTP/2.0 pipeline involves some more components, and a pipeline that supports both is a bit more involved still. By comparison, it’s easy to configure Cro::HTTP::Server to do HTTPS with support for both HTTP/1.1 and HTTP/2.0:

my %tls =
:certificate-file('certs-and-keys/server-crt.pem'),
:private-key-file('certs-and-keys/server-key.pem');
my $server = Cro::HTTP::Server.new: :port(4242), :application(MuskoxApp),
:%tls, :http<1.1 2>;

The route to happiness

A web application in Cro is ultimately always a transform that turns a HTTP request into a HTTP response. It’s very rare to want to process all requests in exactly the same way, however. Typically, different URLs should be routed to different handlers. Enter Cro::HTTP::Router:

use Cro::HTTP::Router;
use Cro::HTTP::Server;
my $application = route {
get -> {
content 'text/html', 'Do you like dugongs?';
}
}
my $server = Cro::HTTP::Server.new: :port(4242), :$application;
$server.start;
react whenever signal(SIGINT) {
$server.stop;
exit;
}

The object returned by a route block does the Cro::Transform role, meaning it would work just fine to use it with Cro.compose(...) plumbing too. It’s a good bit more convenient to write an application using the router, however! Let’s look at the get call a little more closely:

get -> {
content 'text/html', 'Do you like dugongs?';
}

Here, get is saying that this handler will only deal with HTTP GET requests. The empty signature of the pointy block means no URL segments are expected, so this route only applies to /. Then, instead of having to make a response object instance, add a header, and encode a string, the content function does it all.

The router is built to take advantage of Perl 6 signatures, and also to behave in a way that will feel natural to Perl 6 programmers. Route segments are set up by declaring parameters, and literal string segments match literally:

get -> 'product', $id {
content 'application/json', {
id => $id,
name => 'Arctic fox photo on canvas'
}
}

A quick check with curl shows that it takes care of serializing the JSON for us also:

$ curl http://localhost:4242/product/42
{"name": "Arctic fox photo on canvas","id": "42"}

The JSON body serializer is activated by the content type. It’s possible, and pretty straightforward, to implement and plug in your own body serializers.

Want to capture multiple URL segments? Slurpy parameters work too, which is handy in combination with static for serving static assets, perhaps multiple levels of directories deep:

get -> 'css', *@path {
static 'assets/css', @path;
}

Optional parameters work for segments that may or may not be provided. Using subset types to constrain the allowed values work too. And Int will only accept requests where the value in the URL segment parses as an integer:

get -> 'product', Int $id {
content 'application/json', {
id => $id,
name => 'Arctic fox photo on canvas'
}
}

Named parameters are used to receive query string arguments:

get -> 'search', :$query {
content 'text/plain', "You searched for $query";
}

Which would be populated in a request like this:

$ curl http://localhost:4242/search?query=llama
You searched for llama

These too can be type constrained and/or made required (named parameters are optional by default in Perl 6). The Cro router tries to help you do HTTP well by giving a 404 error for failure to match a URL segments, 405 (method not allowed) when segments would match but the wrong method is used, and 400 when the method and segments are fine, but there’s a problem with the query string. Named parameters, through use of the is header and is cookie traits, can also be used to accept and/or constrain headers and cookies.

Rather than chugging through the routes one at a time, the router compiles all of the routes into a Perl 6 grammar. This means that routes will be matched using an NFA, rather than having to chug through them one at a time. Further, it means that the Perl 6 longest literal prefix rules apply, so:

get -> 'product', 'index' { ... }
get -> 'product', $what { ... }

Will always prefer the first of those two for a request to /product/index, even if you wrote them in the opposite order:

get -> 'product', $what { ... }
get -> 'product', 'index' { ... }

Middleware made easier

It’s fun to say that HTTP middleware is just a Cro::Transform, but it’d be less fun to write if that was all Cro had to offer. Happily, there are some easier options. A route block can contain before and after blocks, which will run before and after any of the routes in the block have been processed. So, one could add HSTS headers to all responses:

my $application = route {
after {
header 'Strict-transport-security', 'max-age=31536000; includeSubDomains';
}
# Routes here...
}

Or respond with a HTTP 403 Forbidden for all requests without an Authorization header:

my $application = route {
before {
unless .has-header('Authorization') {
forbidden 'text/plain', 'Missing authorization';
}
}
# Routes here...
}

Which behaves like this:

$ curl http://localhost:4242/
Missing authorization
$ curl -H"Authorization: Token 123" http://localhost:4242/
<strong>Do you like dugongs?</strong>

It’s all just a Supply chain

All of Cro is really just a way of building up a chain of Perl 6 Supply objects. While the before and after middleware blocks are convenient, writing middleware as a transform provides access to the full power of the Perl 6 supply/whenever syntax. Thus, should you ever need to take a request with a session token and make an asynchronous call to a session database, and only then either emit the request for further processing (or do a redirection to a login page), it’s possible to do it – in a way that doesn’t block other requests (including those on the same connection).

In fact, Cro is built entirely in terms of the higher level Perl 6 concurrency features. There’s no explicit threads, and no explicit locks. Instead, all concurrency is expressed in terms of Perl 6 Supply and Promise, and it is left to the Perl 6 runtime library to scale the application over multiple threads.

Oh, and WebSockets?

It turns out Perl 6 supplies map really nicely to web sockets. So nicely, in fact, that Cro was left with relatively little to add in terms of API. Here’s how an (overly) simple chat server backend might look:

my $chat = Supplier.new;
get -> 'chat' {
# For each request for a web socket...
web-socket -> $incoming {
# We start this bit of reactive logic...
supply {
# Whenever we get a message on the socket, we emit it into the
# $chat Supplier
whenever $incoming -> $message {
$chat.emit(await $message.body-text);
}
# Whatever is emitted on the $chat Supplier (shared between all)
# web sockets), we send on this web socket.
whenever $chat -> $text {
emit $text;
}
}
}
}

Note that doing this needs a use Cro::HTTP::Router::WebSocket; to import the module providing the web-socket function.

In summary

This is just a glimpse at what Cro has to offer. There wasn’t space to talk about the HTTP and web socket clients, the cro command line tool for stubbing and running projects, the cro web tool that provides a web UI for doing the same, or that if you stick CRO_TRACE=1 into your environment you get lots of juicy debugging details about request and response processing.

To learn more, check out the Cro documentation, including a tutorial about building a Single Page Application. And if you’ve more questions, there’s also a recently-created #cro IRC channel on Freenode.

Day 8 – Adventures in NQP Land: Hacking the Rakudo Compiler

With apologies to the old Christmas classic, “The Twelve Days of Christmas,” I give you the first line of a Perl 6 version:

On the first day of Christmas, my true love gave to me, a Perl table in a pod tree…

But the table I got wasn’t very pretty!

Background

My first real contact with Perl 6 came in the spring of 2015 when I decided to check on its status and found it was ready for prime time. After getting some experience with the language I started contributing to the docs in places where I could help. One of my first contributions to the docs was to clean up one of the tables which was not rendering nicely . During my experiments with pod tables on my local host I tried the following table:

=begin table
-r0c0 r0c1
=end table

which caused Perl 6 to throw an ugly, LTA (less than awesome) exception message:

"===SORRY!=== Cannot iterate object with P6opaque representation"

I worked around the problem but it nagged at me so I started investigating the guts of pod and tables. That led me to the source of the problem in github.com/rakudo/src/Perl6/Pod.nqp.

In fact, the real problem for many pod table issues turned out to be in that file.

Not Quite Perl (NQP)

nqp is an intermediate language used to build the Rakudo Perl 6 compiler. Its repository is found here. The rest of this article is about modifying nqp code in the rakudo compiler found in its repository here. Rakudo also has a website here.

Before getting too far I first read the available information about Rakudo and NQP here:

Then I started practicing nqp coding by writing and running small nqp files like this (file “hello.nqp”):

say("Hello, world!");

which, when executed, gave the expected results:

$ nqp hello.nqp
Hello, world!

Note that say() is one of the few nqp opcodes that doesn’t require the nqp:: prefix.

Into the trenches

The purpose of the Perl6::Pod class, contained in the rakudo/src/Perl6/Pod.nqp file, is to take pod grammar matches and transform them into Perl 6 pod class definitions, in rakudo/src/core/Pod.pm, for further handling by renderers in Perl 6 land. For tables that means anything represented in any legal pod form as described by the Perl 6 documentation design Synopsis S26, the Perl 6 test suite specs, and the Perl 6 docs has to be transformed into a Perl 6 Pod::Block::Table class object with this form as described in file rakudo/src/core/Pod.pm:

configuration information
a header line with N cells
M content lines, each with N cells

I wanted the nqp table pod handling to be robust and able to automatically fix some format issues (with a warning to the author) or throw an exception (gracefully) with detailed information of problems to enable the author to fix the pod input.

Workspace and tools

I needed two cloned repositories: rakudo and roast. I also needed forks of those same repositories on github so I could create pull requests (PRs) for my changes. I found a very handy Perl 5 tool in CPAN module App::GitGot. Using got allowed me to easily set up all four repos. (Note that got requires that its target repo not exist either in the desired local directory or the user’s github account.) After configuring got I went to a suitable directory to contain both repos and executed the following:

got fork https://github.com/rakudo/rakudo.git
got fork https://github.com/perl6/roast.git

which resulted in a subdirectories rakudo and roast containing the cloned repos and new forks of rakudo and roast on my github account. In the rakudo directory one can see the default setup for easy creation of PRs:

$ git remote -v
origin git@github.com:tbrowder/rakudo.git (fetch)
origin git@github.com:tbrowder/rakudo.git (push)
upstream https://github.com/rakudo/rakudo.git (fetch)
upstream https://github.com/rakudo/rakudo.git (push)

There are similar results in the roast repo.

Next, I renamed the roast repo as a subdirectory of rakudo (“rakudo/t/spec”) so it functions as a subgit of the local rakudo.

Finally, I created several bash scripts to ease configuring rakudo for installation in the local repo directory, setting the environment, and running tests:

  • rakudo-local-config.sh
  • run-table-tests.sh
  • set-rakudo-envvars.sh

(See all scripts mentioned here at https://github.com/tbrowder/nqp-tools.)

To complete the local working environment you will need to install some local modules so you must change your path and install a local copy of the zef installer. Follow these steps in your rakudo directory (from advice from @Zoffix):

git clone https://github.com/ugexe/zef
export PATH=`pwd`/install/bin:$PATH
cd zef; perl6 -Ilib bin/zef install .
cd ..
export PATH=`pwd`/install/share/perl6/site/bin:$PATH
zef install Inline::Perl5

Then install any other module you need, e.g.,

zef install Debugger::UI::CommandLine
zef install Grammar::Debugger

Hacking

Now start hacking away. When ready for a build, execute:

make
make install

The make install step is critical because otherwise, with the local environment we set up, the new Perl 6 executables won’t be found.

Debugging for me was laborious, with rebuilds taking about three minutes each. The debugger (perl6-debug-m) would have been very useful but I could not install the required Debbugger::UI::CommandLine module so it would be recognized by the locally-installed perl6-debug-m. The primary method I used was inserted print statements plus using the --ll-exception option of perl6. Of major note, though, is that this author is a Perl 6 newbie and made lots of mistakes, and did not always remember the fixes, hence this article. (Note I likely would have used the debugging tools but, at the time I started, I did not ask for help and did not have the advice provided shown above.)

Testing

It goes without saying that a good PR will include tests for the changes. I always create a roast branch with the same name as my rakudo branch. Then I submit both PRs and I refer to the roast PR in the rakudo PR and vice versa. I note for the roast PR that it requires the companion rakudo PR for it to pass all tests.

See Ref. 5 for much more detail on specialized test scripts for fudging and other esoteric testing matters.

Documentation

I try to keep the Perl 6 pod table documentation current with my fixes.

NQP lessons learned

  • LTA error messages are a fact of life, e.g., “Cannot invoke this object…”, which can be caused by many things, including a misspelled identifier (NQP issue filed, early report is it may be impossible to fix anytime soon).

  • Ensure all nqp opcodes have the nqp:: prefix (except the few built-ins)

  • Practice with new code in an nqp-only sand-box.

Success!

I have now had two major Perl 6 POD (and roast) PRs accepted and merged, and am working on one more “easy” one which I should finish this week. The PRs are:

  1. Rakudo PR #1240

The Rakudo PR provided fixes for RTs #124403, #128221, #132341, #13248, and #129862. It was accompanied by roast PR #353.

The PR allowed the problem table above to be rendered properly. It also added warnings for questionable tables, added Rakudo environment variables RAKUDO_POD6_TABLE_DEBUG to aid users in debugging tables (see docs, User Debugging), and allows short rows with empty columns to be rendered properly.

  1. Rakudo PR #1287

The Rakudo PR provided a fix for Rakudo repo issue #1282. It was accompanied by roast PR #361. (Note that roast PR #361 is not yet merged.)

The PR allows table visual column separators (‘|’) and (‘+’) to be used as cell data by escaping them in the pod source.

Summary

  • Perl 6 pod is a great improvement over Perl 5, but it is still not fully implemented.

  • Working in the bowels of Rakudo Perl is rewarding (and fun), but prepare to get your hands dirty!

  • The Perl 6 community is a great group to be associated with.

  • I love Rakudo Perl 6.

Merry Christmas and Happy Hacking!

Credits

Any successful inputs I have made are due to all the Perl 6 core developers and the friendly folks on IRC (#perl6, #perl6-dev).

References

  1. JWs Perl 6 debugger Advent article
  2. JWs Rakudo debugger module Debugger::UI::CommandLine
  3. JWs grammar debugger module Grammar::Debugger
  4. Testing Rakudo
  5. Contributing to roast
  6. Github guide to pull requests (PRs)
  7. Perl 6 documentation (docs)

Appendix

POD tools

  • perl6 –doc=MODULE # where ‘MODULE’ is ‘HTML’, ‘Text’, or other appropriate module
  • p6doc
  • perl6 –ll-exception

Major Perl 6 POD renderers

Day 7 – Test All The Things

Perl 6, like its big sister Perl 5, has a long tradition of testing. When you install any Perl module, the installer normally runs that module’s test suite. And of course, as a budding Perl 6 module author, you’ll want to create your own test suite. Or maybe you’ll be daring and create your test suite before creating your module. This actually has several benefits, chief among them being your very first user, even before it’s written.

Before getting to actual code, though, I’d like to mention two shell aliases that I use very frequently –

alias 6='perl6 -Ilib'
alias 6p="prove -e'perl6 -Ilib'"

These aliases let me run a test file quickly without having to go to the trouble of installing my code. If I’m in a project directory, I can just run

$ 6 t/01-core.t
ok 1 - call with number
ok 2 - call with text
ok 3 - call with formatted string
1..3

and it’ll tell me what tests I’ve run and whether they all passed or not. Perl 6, just like its big sister Perl 5, uses the ‘t/’ directory for test files, and by convention the suffix ‘.t’ to distinguish test files from packages or scripts. It’s also got a built-in unit testing module, which we used above. If we were testing the sprintf() internal, it might look something like

use Test;

ok sprintf(1), 'call with number';
ok sprintf("text"), 'call with text';
ok sprintf("%d",1), 'call with formatted string';

done-testing;

The ok and done-testing functions are exported for us automatically. I’m using canonical Perl 6 style here, not relying too much on parentheses. In this case I do need to use parentheses to make sure sprintf() doesn’t “think” ’empty call’ is its argument.

ok takes just two arguments, the truthiness of what you want to test, and an optional message. If the first argument is anything that evaluates to True, the test passes. Otherwise… you know. The message is just text that describes the test. It’s purely optional, but it can be handy when the test fails as you can search for that string in your test file and quickly track down the problem. If you’re like the author, though, the line number is more valuable, so when you see

not ok 1 - call with number
# Failed test 'call with number'
# at test.t line 4
ok 2 - call with text
ok 3 - call with formatted string
1..3

in your test, you can immediately jump to line 4 of the test file and start editing to find out where the problem is. This gets more useful as your test files grow larger and larger, such as my tests for the Common Lisp version of (format) that I’m writing, with 200+ tests per test file and growing.

Finally, done-testing simply tells the Test module that we’re done testing, there are no more tests to come. This is handy when you’re just starting out and you’re constantly experimenting with your API, adding and updating tests. There’s no test counter to update each time or any other mechanics to keep track of.

It’s optional, of course, but other tools may use the ‘1..3’ at the end to prove that your test actually ran to completion. The tool prove is one, Jenkins unit testing and other systems may need that as well.

It depends…

on what your definition of ‘is’ is. While the ok test is fine if you’re only concerned with the truthiness of something, sometimes you need to dig a little deeper. Perl 6, just like its big sister, can help you there.

is 1 + 1, 2, 'prop. 54.43, Principia Mathematica';

doesn’t just check the truthiness of your test, it checks its value. While you could easily write this as

ok 1 + 1 == 2, 'prop. 54.43, Principia Mathematica';

using is makes your intent clear that you’re focusing on whether the expression 1+1 is equal to 2; with the ok version of the same statement, it’s unclear whether you’re testing the ‘1 + 1’ portion or the ‘==’ operator.

These two tests alone cover probably a good 80% of your testing needs, is handles basic lists and hashes with relative aplomb, and if you really need complex testing, its big sister is-deeply is standing at the wayside, ready to handle complex hash-array combinations.

Laziness and Impatience

Sometimes you’ve got a huge string, and you only need to check just a little bit of it.

ok 'Lake Char­gogg­a­gogg­man­chaugg­a­gogg­chau­bun­a­gung­a­maugg' ~~ 'manchau', 'my side';

You can certainly use the ~~ operator here. Just like ‘1 + 1 == 2’, though, your intent might not be clear. You can use the like method to make your intentions clear.

like 'Lake Char­gogg­a­gogg­man­chaugg­a­gogg­chau­bun­a­gung­a­maugg',
     /manchau/, 'my side';

and not have the ~~ dangling over the side of your boat.

DRYing out

After spending some time on and in beautiful Lake Char­gogg­a­gogg­man­chaugg­a­gogg­chau­bun­a­gung­a­maugg, you probably want to wring your clothes out. Test files tend to grow, especially regression tests. You might find yourself writing

is sprintf( "%s", '1' ), '1', "%s formats numbers";
is sprintf( "%s", '⅑' ), '⅑', "%s formats fractions";
is sprintf( "%s", 'Ⅷ' ), 'Ⅷ', "%s formats graphemes";
is sprintf( "%s", '三' ), '三', "%s formats CJKV";

That’s fine, copying and pasting (especially from StackOverflow) is a time-honored tradition, nothing wrong with that. Consider though, what happens when you add more tests with “%d” instead of “%s”, and since all of those strings are numbers, you just copy and paste the block, change “%s” to “%d” and go on.

is sprintf( "%s", '1' ), '1', "%s formats numbers';
# ...

is sprintf( "%d, '1' ), '1', "%d formats numbers';
# ...

So now you’ve got two sets of tests with the same names. Rather than editing all of the new “%d” tests, wouldn’t it be nice if we didn’t have to repeat ourselves in the first place?

subtest '%s', {
    is sprintf( "%s", '1' ), '1', "formats numbers";
    is sprintf( "%s", '⅑' ), '⅑', "formats fractions";
    is sprintf( "%s", 'Ⅷ' ), 'Ⅷ', "formats graphemes";
    is sprintf( "%s", '三' ), '三', "formats CJKV";
};

Now you just need to edit things in two places rather than three. If this has whetted your appetite for testing, I’d encourage you as well to check out Test All The Things at my personal site for more advanced testing paradigms and more advanced Perl 6 code. Also don’t forget to stay tuned for tomorrow’s Perl 6 Advent posting!

Thank you, and happy hacking!

DrForr aka Jeff Goff, The Perl Fisher

Day 6 – Five golden rings, Four calling birds, Three French hens, Two kinds of programmers?, And a book review in a Perl tree! (or Rakudo Tree? ;-)

PREFACE

In the following, this novice programmer will try to make the case for two kinds of programmers, which I then use as a springboard to my review of Think Perl 6, the Perl 6 introduction to programming book.

A little about me: I learned my first coding language summer of 2017.  My interest in programming started around the year 2000, when I was in the 8th Grade.  (Spare you the math, I’m 31 years old, trying to enter programming career without a degree.)  It was actually that book I got in 8th Grade that I read this summer, C– How To Program (I kid about the minuses.)  It was really neat to open that book and see the old Amazon bookmark of that time, and even where I had stopped reading.

I’ll touch real quick on the question, Is Perl 6 a good beginning code language?  Short answer, if only the imperative paradigm is taught first.  I think the beginner finds it comforting to know what every character in the program does.  So, the idea of introducing objects before the beginner knows what functions are, just doesn’t sound right to me.  I prefer the old-school method of learning first control structures, then functions, arrays, pointers, strings and characters, I/O, THEN classes.

I do think Perl 6’s lack of strict typing is a major disadvantage, because developing the mental muscles of keeping track of data types is a good idea, as well as enforcing the Principle of Least Privilege.  Perhaps if a Perl 6 author were to use code that adhered to this strict typing 100% of the time, that would be enough to train the novice in the way they should go.  I think it requires much repetition to drill into the untrained mind that values can be limited to types, and that this is a good thing.  In short, I don’t think a quick paragraph discussing types does the topic justice.  It must be encountered frequently.

The chief quality I nurtured in programming was to understand how programs work, rather than a desire to build something.  This difference summarizes the main argument of my article, which is that some people prefer to stay in the shallow-end of the pool and to simply understand, while others have a stronger desire to do more than just understand, but to actually build something.

I wonder if for those more interested in building, they more-or-less don’t care what .say is, rather they just care that it prints what they want to say.  So for a do-er type person, I wonder if they don’t care which paradigm they learn first.  For such an one, maybe Perl 6 is fine for a first programming language.

Finally, your calibration of the accuracy of this article will be skewed if I do not express to you what kind of thinker I am , and what sort of programmer I would be.  I say this because I perceive that I’m much different than the typical pursuer of programming knowledge, and this review may be vastly out-of-touch with the majority.  So we will take a detour on that subject real quick.

From my browsing of the internet, in those places where people that inspire to be programmers come to the watering holes of knowledge (Stackoverflow.com, Quora, Youtube, et cetera), I’ve discovered there seem to be two different kinds of programmers. The first is the stereotypical programmer, what I refer to in this article as the Computer Scientist (CS) — people that math hard, naturally talented, self-taught, can use a reference manual as a primary learning source, and so forth.

The other kind is the lowly Information Technology (IT) group – people that are better with computers than the average population but typically not fans of math, not able to effortlessly “pick up” command prompts like bash or even IRC or reference manuals, and frankly, they just aren’t as into computers as much as the CS guys. This IT group, I believe , is the majority of people interested in programming. One of the most popular questions associated with programming and beginners is, Do you have to be good at math to be a programmer? Notice I say majority of the people INTERESTED. I believe that the vast majority of ACTUAL programmers are the CS-type.

Whether you have a degree or not is not the point I’m getting at.  I chose to use those terms because a recent video I watch (https://www.youtube.com/watch?v=hT7RNAq-zvo) explained the difference between the two collegiate degrees which was a recent revelation to me.

Anyway, I am the IT kind of programmer.  So it is from this background, Perl6er, that I present to you my thoughts on your programming language’s leading book for novices of programming, Think Perl 6.  So take my opinion for whatever it’s worth.

REVIEW

The very second paragraph of Think Perl 6 is interesting because it touches the heart of this article.  The author states, “The single most important skill for a computer scientist is problem solving.”  I may be completely scornfully naive because I have zilch experience with programming, but I’m hoping for this statement to be wrong.

Working through a first programming book, I believe most beginners wrestle with the idea, am I cut-out for programming?  I’ve meditated on this, and I found that the ideal job description for me would be working on existing code that I debug or slightly modify. Certainly, this still requires problem solving, but I think the association of “problem solving” in computer programing is math word problems.  In short, I think most of these IT types are turned off by this phrase “problem solving”, regardless of how the author intended it.

THE BOOK IS DESIGNED FOR CS GUYS

Now back to the question, Is the current book for Perl 6 the right book for novices of programming?  For CS type guys, I would say, “Sure.”  The book has like 80 pages of solutions to practice problems, and I think the pace of the book is right down their alley.

So the rest of the article is geared to those IT programmers that need their hands held and “walked-through” the book.

Let me start off by saying that I have contacted the author to inform him of my pending review, and he was VERY courteous in his response to me.  He didn’t know this was going to be an Advent post, and neither did I until I chatted with some eager folks on IRC a few day ago.

I don’t wish to lambaste the author, I am merely recording what notes I took during my process of reading the text, with no respect of persons to who or what the author was or his status.  I’m focusing on the negative aspects of the book because that’s what invariably gets noted in a book.  But I will say real quick, the author does an outstanding job of summarizing the totality of programming on Page 4 better than anyone else I’ve read (I’ve now read a total of 3 programming books and two networking books), does well using comedy, explained modulus well and taught me something new about it, presents well some unique strengths of Perl 6’s: nested conditionals (p.62), for range-loop (p.64); and did an amazing job with a very clean example of recursion on Page 66, his tip on Incremental Development (p.79) was new to me and helpful, tip on debugging new to me and helpful(p.106).

TOPICS TAUGHT IN SOLUTIONS

I believe many people new to programming prefer to read the book through without doing any coding.  I know, I know, this is pretty much universally considered to be the wrong thing to do.  Regardless, I think the strongest reason for people doing so is because of the question, Am I really cut-out to be a programmer?  The fastest way to answer that question is to read through the book quickly, which means skipping the practice problems.

So one of the pitfalls to me of this book was as the author explains it on Page iii, “the solution section of the Appendix also introduces examples of topics that will be covered in the next chapter – and sometimes even things that are not covered elsewhere in the book” — meaning some topics are ONLY covered in the practice exercise solutions.  It only recently occurred to me that I could have gone directly to the answer section in the appendix.  But anyway, the material being separated to the back means many beginners will do what I did, just move on to the next chapter.

CODE SNIPPETS VS. COMPLETE PROGRAMS

I started my journey in programming the summer of 2017 reading the book C++ How To Program by Deitel.  It was a blessing that I started on this book because from what I can gather, this seems to be one of the few introduction to programming books that presents the reader with COMPLETE programs and their output to the screen and not just code snippets.  And, he does this for ALL the chapters.

The output was very important for me to figure out what was going on.  It helps tremendously when you see the value the author entered-in, and you can use his value to verify your understanding of the program is correct.

It was when I bought my second C++ book (Stroustup’s Programming) that I realized that I preferred complete programs because Stroustrup, like most other authors of today, only use short examples of code (snippets).

I was not able to “absorb” what Stroustrup was explaining even though he was teaching the basics which I had already learned.  It was and still is discouraging (and fascinating) to me that a certain method seems to be a requirement for me to learn; that is, that the author “holds my hand” and “walks me through the book”.  However, this lack of being able to read most of the computer books I encounter is the main contributor to the question, Am I cut-out to be a programmer?

No doubt this crutch of needing complete programs to understand is associated with the route I took – of just reading the book rather than doing exercises.  But I feel there is more to the picture.

I believe some people learn better reading code than writing code.  Or another way of saying it, I believe some people are better equipped to take jobs that require just reading code and modifying it, than developing new software.  This leads into the mysterious subject of various types of programming job descriptions, which seem to be an elusive hidden topic.  But anyways, on to the review.

THE BOOK LOOKS LIKE IT WAS RUSHED

Page XV describes the font conventions that will be used in the book: italics, bold, c o n s t a n t widths, and icons! — of a lemur for tips — a crow for general comments — and a scorpion for warnings.  However, these icons were never used in the book, and I never saw a bold word in the entire book, aside from section titles.  I didn’t see constant width used.

On Page 32, the author cites proper examples as

> round 42.45, 1;

42

> round 42.45, .1;

42.5

> round(42.45, .1);

42.5

>round( 42.45, .1);

42.5

but forgets a format he himself uses often throughout the book:

round (42.45, .1);

As I worked through the book, I kept wondering if the space was an error or not.  This may seem like nit-picking, but when someone is new to programming, they shouldn’t be concerned whether there are typos in what they are trying to learn.  This leads to thoughts of whether they bought the right book or not, or whether this programming code language community is professional or not, et cetera.

I know what you’re thinking, “Just go type it into a computer, you lazy fool.”  All I can say to my defense is that I grab these books and start reading.  I hate interrupting reading to type in code.

This goes back to what we talked about earlier, a beginner is more likely to want to get through the book quickly and skip coding.  Besides, beginners inevitably will have problems getting editors running, and command prompt issues.  So its best to make it easy for them to not need to.  It happened with my first book, as well. C++ How To Program 2nd edition was written in 1998?.  And it was tough finding an easy-to-install IDE; and then when I tried the code, it was outdated.  (No std::cout back then.)  So, I just went back to reading the book, instead of hassling to get things working to code.

Chapter 7 glossary includes the terms “item” and “slice” which are introduced in Chapter 9.  This is frustrating as a diligent reader will go back and re-read the chapter, assuming that they forgot the material.  And there are other details, which I won’t bore us with.  In summary, I felt the book was done in a hurry.

EXAMPLES WERE NEEDED OF:

the difference between ++variable and variable++ in a loop (p.20)

a function that returns void (p.43)

difference between a function and a function “mutator” (p.43)

what a caller to a function is (p.44). The author assumed the reader knew what a caller was. Page 40 was where the author introduces a code example involving a caller, but the author did not explain the function call.

to show where “if” or “when” needs to be used (p.89)

to show what implementing a dispatch table as an array means (p.198)

CODE NOT EXPLAINED

Author uses comment in example on Page 7, but doesn’t explain comments until p.25. This is discouraging because I remember when I was learning C++ the author carefully explaining each line of code, which was a comfort.

No explanation of: the comma in say ‘The answer is ‘, $value Page 22. I wondered if it was a typo.

necessity of ( ) for a variable representing a no-name function (p.48)

$*IN (p.69)

\n (p.99)

~$0 (p.117)

parentheses in regex /(<[\d.-]>+)/ (p.121)

m: (regex match operator) (p.126)

rx (p.128)

s/ / / operator (p.130)

handle (member-function of class IO) (p.141)

No explanation of bottom of Page 159, last line of code. I can’t understand my notes by just glancing at them, but there is some confusion with 1..3 being confused with [1], [2], [3].

Author didn’t explain why $_ is now needed for this example (p.168)

\t (p.189)

colon (p.190).

(Does this colon operator have a name?)

isa (p.240)

atan2 (p.243)

reduction operator (p.207)

THIS IS NOT A GENERAL BOOK ABOUT PROGRAMMING

I disagree with the author’s opening paragraph where he says, “this book is less about Perl 6, and more about learning how to write programs for computers.”

The author doesn’t mention anything in the book about the most fundamental element of good software design, which is the Principle of Least Privilege.

The author doesn’t introduce the term “identifier” (p.15 would be the area to do it) which is very important in a world of abstraction and names.

Author doesn’t explain what typed variables are and how they, not scalar variables, are used in most coding languages (p.16).

The author does not differentiate between assigning and initializing a variable (p.19). Initializing first gets mentioned on Page 97.

“Script” is defined as a file, rather than a small program (p.21).

Author does not tell reader what I/O stands for (p.139) And carriage return never explained (p.141).

ODDS AND ENDS

Confusing word choice for a novice: “non-alphanumerical” vs. “a symbol”, bijective (p.193).

Author talked about the necessity of declaring variables before you can use that variable (p.16), but in the first example that has two variables (p.23), he doesn’t remind the reader by demonstrating a declaration. It is assumed the variable is declared, which is confusing to the beginner, as he never stated it was assumed to be declared.

Author doesn’t tell reader how to pronounce ~ (p.24), and same thing with & (p.47).

Type conversion not explained (p.33).

Explanation of flow of execution was much too short (p.39).

Author doesn’t tell reader what things stand for: is rw

Author doesn’t explain first-class citizens (p.47).

Author gives the reader the code first, then explains later: p. 57, p.64, 109-110, 121. I prefer the explanation first, then the code, because I stay at that code focusing intensely if I am forgetting something I read before that would explain my confusion.

Significant typo on Page 161. Correct output reads: [1 2 3 4 5 6 7 8 9].

Index and glossary were not immaculate: twigil not in Ch. 9 glossary, index does not include $/ (p.118), .. (p.64, => (p.184) <=> (p.173), “data structure” 221 (correction: p.1, 145*, 157, 178, 221), “pointy block” needs pages 113 and 70 included, “state” needs p.198 included, topical variable needs pages 88 and 113 included.

CONCLUSION

I want to thank the author for writing this book. Without it I wouldn’t have met this nice Perl 6 community, and I also wouldn’t have been introduced to this Declarative Programming paradigm that looks so interesting. I read the book in the midst of me also reading other computer science books and learning C, so my brain is a mess. However, the more I learn about computing, the more Perl 6 looks like a sleeper car. You know, in street racing, how people have cars that look slow, but are actually very fast.

And finally, if there’s going to be a throwing-in of possible Perl 6 aliases, I’m submitting 6lerp (pronounced slurp)!  Stay warm out there folks, both inside and out.

-COMBORICO1611

Day 5 – Destructure your Arguments with Perl 6 Signatures

Among dozens of other key Perl 6 features, I consider Signatures one of the many ‘killer’ features. They are so full of functionality and so powerful, I suspect a whole book could be written on how to use them well. I want to explore one specific bit of functionality I originally overlooked, but I’ve come to cherish.

You’ve probably seen the basic subroutine signatures:

sub myfunc($x, $y, $z) {...}

This declares 3 scalar parameters for the function, and gives them the names $x, $y, and $z within the body of the function.

Simple stuff.

You can get fancier, giving them specific types:

sub myfunc(Str $x, Int $y, Rat $z) {...}

You can use smilies to require the values to be defined:

sub myfunc(Str:D $x, Int:D $y, Rat:D $z) {...}

There are many other fancy specifiers you can use I won’t get into here.

But what if your parameter is more complex? (NOT Complex – though that works too..)

For example, you might want to restrict a specific parameter to a Positional argument like an Array, or an Associative one like a Hash using the respective sigils, @ or %.

sub myfunc(%h) {...}

Now I can call the function with a hash:

myfunc(%( a => 1, b => 'this', c => 2.2));

If I want to verify that those specific fields are present, I can put code in the top of my function to do that:

If I want to also simplify the way I refer to those fields, I can assign them to other variables:

Kind of tedious, right?

Perl signature parameter destructuring to the rescue! We can do all that right in the subroutine signature itself  ― just put a sub-signature behind.

sub myfunc(%h (Int :$a, Str :$b, Rat :$c)) {...}

Destructuring JSON

Pretty nice, but what if you’ve got something even MORE complicated.

Say a chunk of JSON with nested structures, parts that might be missing that need defaults, etc.

The q:to/END/ is a Perl 6 heredoc that just sucks in the text verbatim up to the END, then we can use the JSON::Fast from-json() to parse it into a perl data structure. You can describe your whole JSON structure right in the signature for a function that you want to receive something like that:

Now in the body, I can refer to the parts as just $title, $author, $count, and @tags. I’ve also split out tags into $first-tag and @other-tags for convenience.

Don’t forget you can use Signatures for Blocks too

Sure, Signatures are fantastic for subroutines, but you can also use them, and the destructuring, for a block. Suppose you had an array of the JSON items above, and wanted to iterate through them with a for loop? Just use the destructuring signature for the pointy block of the for:

Note in this case I don’t even need the hash itself, so I’ve omitted a name for it, using just % by itself for an anonymous Hash (Associative).

Destructuring even works for Objects!

Have you ever tried to walk through an array of objects where the first thing you do is call a few accessors to grab some of the attributes?  Sure, you could just use .attribute with the topicalized iterator, but with a sub-signature, you can do even more.

If you want to check for type, or definedness, or set a default, you can do it right in the Signature. If you don’t like the object attribute names, you can use aliases to rename them as you please too.

Conclusion

I’ve found destructuring parameters very useful in interacting with database query results and JSON. You can use any of the other features of signatures like this, including specifying type, definedness, optionalness, default values, renaming with aliases, limiting with subsets or “where” clauses, slurpies, etc.

Happy Holidays!