Perl 6 Colonpairoscopy

Read this article on Rakudo.Party

If I were to pick the most ubiquitous construct in the Perl 6 programming language, it'd most definitely be the colonpair. Hash constructors, named arguments and parameters, adverbs, and regex modifiers—all involve the colonpair. It's not surprising that with such breadth there would be many shortcuts when it comes to constructing colonpairs.

Today, we'll learn about all of those! Doing so will have us looking at the simplest as well as some of the more advanced language constructs, so if parts of this article make you scratch your head, don't worry—you don't have to learn all of it at once!

PART I: Creation

Colonwhaaaa?

The colonpair gets its name from (usually) being a Pair object constructor and (usually) having a colon in it. Here are some examples of colonpairs:

:foo,
:$bar,
:meow<moo>,
heh => hah

The last one doesn't have a colon in it, but since it's basically the same thing as other colonpairs, I personally consider it a colonpair as well.

We can see the colonpairs make Pair objects by dumping their .^namemethodname):

say :foo.^name; # OUTPUT: «Pair␤»

However, when used in argument lists, the colonpairs are specially handled to represent named arguments. We'll get to that part later in the article.

The Shortcuts

Here's a mostly-complete list of available ways to write a colonpair you can glance over before we dive in. I know, it looks like a huge list, but that's why we're reading this article—to learn the general patterns that make up all of these permutations.

# Standard, take-any-type, non-shortcut form
:nd(2).say;             # OUTPUT: «nd => 2␤»
:foo('foo', 'bar').say; # OUTPUT: «foo => (foo bar)␤»
:foo( %(:42a, :foo<a b c>) ).say;
# OUTPUT: «foo => {a => 42, foo => (a b c)}␤»

# Can use fat-arrow notation too:
# (parentheses around them are here just for the .say call)
(nd => 2).say; # OUTPUT: «nd => 2␤»
(foo => ('foo', 'bar') ).say; # OUTPUT: «foo => (foo bar)␤»
(foo => %(:42a, :foo<a b c>) ).say;
# OUTPUT: «foo => {a => 42, foo => (a b c)}␤»

# Booleans
:foo .say; # OUTPUT: «foo => True␤»
:!foo.say; # OUTPUT: «foo => False␤»

# Unsigned integers:
:2nd   .say; # OUTPUT: «nd => 2␤»
:1000th.say; # OUTPUT: «th => 1000␤»

# Strings and Allomorphs (stings that look like numbers are Str + numeric type)
:foo<bar>      .say; # OUTPUT: «foo => bar␤»
:bar<42.5>     .say; # OUTPUT: «bar => 42.5␤»
:bar<42.5>.perl.say; # OUTPUT: «:bar(RatStr.new(42.5, "42.5"))␤»

# Positionals
:foo['foo', 42.5] .say; # A mutable Array:   OUTPUT: «foo => [foo 42.5]␤»
:foo<foo bar 42.5>.say; # An immutable List: OUTPUT: «foo => (foo bar 42.5)␤»
# angled brackets give you allomorphs!

# Callables
:foo{ say "Hello, World!" }.say;
# OUTPUT: «foo => -> ;; $_? is raw { #`(Block|82978224) ... }␤»

# Hashes; keep 'em simple so it doesn't get parsed as a Callable
:foo{ :42a, :foo<a b c> }.say; # OUTPUT: «foo => {a => 42, foo => (a b c)}␤»

# Name and value from variable
:$foo;  # same as :foo($foo)
:$*foo; # same as :foo($*foo)
:$?foo; # same as :foo($?foo)
:$.foo; # same as :foo($.foo)
:$!foo; # same as :foo($!foo)
:@foo;  # same as :foo(@foo)
:@*foo; # same as :foo(@*foo)
:@?foo; # same as :foo(@?foo)
:@.foo; # same as :foo(@.foo)
:@!foo; # same as :foo(@!foo)
:%foo;  # same as :foo(%foo)
:%*foo; # same as :foo(%*foo)
:%?foo; # same as :foo(%?foo)
:%.foo; # same as :foo(%.foo)
:%!foo; # same as :foo(%!foo)
:&foo;  # same as :foo(&foo)
:&*foo; # same as :foo(&*foo)
:&?foo; # same as :foo(&?foo)
:&.foo; # same as :foo(&.foo)
:&!foo; # same as :foo(&!foo)

Let's break these up and take a closer look!

Standard, Take-any-Type, Non-Shortcut Form

The "standard" form of the colonpair consists of a colon (:), a valid term that functions as the .key of the created Pair object, and then a set of parentheses inside of which is the expression with the .value for the Pair:

:nd(2).say;                       # OUTPUT: «nd => 2␤»
:foo('foo', 'bar').say;           # OUTPUT: «foo => (foo bar)␤»
:foo( %(:42a, :foo<a b c>) ).say;
# OUTPUT: «foo => {a => 42, foo => (a b c)}␤»

As long as the key is a valid identifier, all other forms of colonpairs can be written using this way. And for non-valid identifiers, you can simply use the .new method—Pair.new('the key','value')—or the "fat arrow" syntax.

Fat Arrow Syntax

If you ever used Perl 5, you need no introductions to this syntax: you write the key—which will get auto-quoted if it's a valid identifier, so in those cases you can omit the quotes—then you write => and then you write the value. The quotes around the key are required if the key is not a valid identifier and the fat arrow is the only operator-involved syntax that will let you construct Pairs with such keys:

# (outer parentheses are here just for the .say call)
(nd => 2).say; # OUTPUT: «nd => 2␤»
(foo => ('foo', 'bar') ).say; # OUTPUT: «foo => (foo bar)␤»
(foo => %(:42a, :foo<a b c>) ).say;
# OUTPUT: «foo => {a => 42, foo => (a b c)}␤»
("the key" => "the value").say; # OUTPUT: «the key => the value␤»

There are some extra rules with how this form behaves in argument lists as well as sigilless variables and constants, which we'll see later in the article.

Boolean Shortcut

Now we start getting into shortcuts! What would the most common use of named parameters be? Probably, to specify boolean flags.

It'd be pretty annoying to always have to write those as :foo(True), so there's a shortcut: simply omit the value entirely, and if you want :foo(False), omit the value and put the negation operator) right after the colon:

# Booleans
:foo .say; # OUTPUT: «foo => True␤»
:!foo.say; # OUTPUT: «foo => False␤»

# Equivalent calls:
some-sub :foo :!bar :ber;
some-sub foo => True, bar => False, ber => True;

The shortcut form is a lot shorter. This is also the form you may see in adverbs and regex syntax, such as the :g adverb on the m// quoter and :s/:!s significant whitespace modifier inside the regex:

say "a b c def g h i" ~~ m:g/:s \S \S [:!s \S \s+ \S]/;
# OUTPUT: «(「a b c d」 「f g h i」)␤»

Here's also another trick from my personal bag: since Bool type is an Int, you can use boolean shortcuts to specify Int values 1 and 0:

# set `batch` to `1`:
^4 .race(:batch).map: { sleep 1 };
say now - ENTER now; # OUTPUT: «1.144883␤»

However, for clarity you may wish to use unsigned integer colonpair shortcut instead, which isn't much longer.

Unsigned Integer Shortcut

The Perl 6 programming language lets you grab an nth match when you're matching stuff with a regex:

say "first second third" ~~ m:3rd/\S+/;
# OUTPUT: «「third」␤»

As you can probably surmise by now, the :3rd after the m in m// quoter is the adverb, written as a colonpair in unsigned integer shortcut. This form consist of a colon and the name of the key with unquoted unsigned integer value placed between them. No signs, no decimal dots, and not even underscore separators between digits are permitted.

The primary use of this shortcut is for things with ordinal suffixes like :1st, :2nd, :9th, etc. It offers great readability there, but personally I have no reservations about using this syntax for all unsigned integer values, regardless of what the name of the key is. It feels slightly offcolour when you first encounter such syntax, but it quickly grows on you:

some-sub :1st :2nd :3rd :42foo :100bar;
^4 .race(:1batch).map: { sleep 1 };

Hash/Array/Callable Shortcuts

Using standard colonpair format you may notice some forms are too parentheses-heavy:

:foo(<42>)                 # value is an IntStr allomorph
:foo(<a b c>)              # value is a List
:foo([<a b c>])            # value is an Array
:foo({:42foo, :100bar})    # value is a Hash
:foo({.contains: 'meows'}) # the value is a Callable

In these form, you can simply omit the outer parentheses and let the inner brackets and curlies do their job:

:foo<42>                   # value is an IntStr allomorph
:foo<a b c>                # value is a List
:foo[<a b c>]              # value is an Array
:foo{:42foo, :100bar}      # value is a Hash
:foo{.contains: 'meows'}   # the value is a Callable

It looks a lot cleaner and is simpler to write. Both the Hash and Callable use the same set of curlies and the same simple rules as used by the {…} construct elsewhere in the language: if the content is empty, or contains a single list that starts with a Pair literal or %-sigiled variable, and the $_ variable or placeholder parameters are not used, a Hash is created; otherwise a Block (Callable) is created.

The angle bracket form (:foo<…>) follows the same rules as the angle bracket quoter used elsewhere in the language:

:foo< 42  >.value.^name.say; # OUTPUT: «IntStr␤»
:foo<meows>.value.^name.say; # OUTPUT: «Str␤»
:foo<a b c>.value.^name.say; # OUTPUT: «List␤»

And keep in mind that these two forms are not equivalent:

:42foo
:foo<42>

The first creates an Int object, while the second one creates an IntStr object, which is an allomorph. This difference is important for things that care about object identity, such as set operators

Sigiled Shortcut

The one thing I find a pain in the bit to write in other languages is constructs like this:

my $the-thing-with-a-thing = …
…
some-sub the-thing-with-a-thing => $the-thing-with-a-thing;

It's fairly common to name your variables the same as some named argument to which you wish to pass that variable as a value. The Perl 6 programming language offers a colonpair shortcut precisely for that case. Simply prepend a colon to the variable name to construct a colonpair with the key named the same as the variable (without including the sigil) and the value being the value of that variable. The only catch is the variable must have a sigil, so you can't use this shortcut with sigilless variables or constants.

my $the-thing-with-a-thing = …
…
some-sub :$the-thing-with-a-thing;

You'll notice that the syntax above looks exactly like how you'd declare a parameter that takes such a named argument—consistency is a good thing. All available sigils and twigils are supported, which makes the full list of variants for this shortcut look something like this:

# Name and value from variable
:$foo;  # same as :foo($foo)
:$*foo; # same as :foo($*foo)
:$?foo; # same as :foo($?foo)
:$.foo; # same as :foo($.foo)
:$!foo; # same as :foo($!foo)
:@foo;  # same as :foo(@foo)
:@*foo; # same as :foo(@*foo)
:@?foo; # same as :foo(@?foo)
:@.foo; # same as :foo(@.foo)
:@!foo; # same as :foo(@!foo)
:%foo;  # same as :foo(%foo)
:%*foo; # same as :foo(%*foo)
:%?foo; # same as :foo(%?foo)
:%.foo; # same as :foo(%.foo)
:%!foo; # same as :foo(%!foo)
:&foo;  # same as :foo(&foo)
:&*foo; # same as :foo(&*foo)
:&?foo; # same as :foo(&?foo)
:&.foo; # same as :foo(&.foo)
:&!foo; # same as :foo(&!foo)

This about wraps up the list of currently available colonpair shortcuts. As you can see, the huge list of shortcuts was reduced to a few simple patterns to follow. However, this might not be all the shortcuts that will exist for all the time…

The Future!

While currently aren't available, the following two shortcuts might become part of the language in future language versions.

The first one is the indirect lookup shortcut. If you have a named variable and the name of that variable in another variable, you can access the value of the first variable using the indirect lookup construct:

my $foo = "bar";
my %bar = :42foo, :70bar;
say %::($foo); # OUTPUT: «{bar => 70, foo => 42}␤»

If you squint, the indirect lookup is sort'f like a sigilled variable and colonpair shortcuts for sigilled variables exist, so it makes sense for the language to be consistent and support indirect lookup colonpair shortcut, which would look something like this, where the value of $foo contains the name of the key for the colonpair.

:%::($foo)

This form is currently listed as simply unimplemented feature in R#1532, so it'll likely see life some day.

The second possible future construct is the :.foo form, which was proposed in RFC R#1462. This form calls method .foo on the $_ topical variable and uses the return value as the value for the created Pair, with the name of the method being the name of the key.

This form comes up semi-frequently when you're passing values of attributes of one object to another with similarly-named attributes, so something like this:

Some::Other.new: :foo(.foo) :bar(.bar) :ber(.ber) with $obj

Would in shortcut form be written like this:

Some::Other.new: :.foo :.bar :.ber with $obj

At the time of this writing, this RFC has been self-rejected, but you never know if there'd be more calls for introduction of this syntax.

PART II: Use

Now that we're familiar with how to write all the forms of colonpairs, let's take a look at some of their available uses, especially those with special rules.

Parameters

To specify that a parameter should be a named rather than a positional parameter, simply use the sigilled variable colonpair shortcut:

sub meow($foo, :$bar) {
    say "$foo is positional and $bar is named";
}
meow 42, :100bar; # 42 is positional and 100 is named
meow :100bar, 42; # 42 is positional and 100 is named

Since parameters need some sort of a variable to bind their stuff to, pretty much all other forms of colonpairs are not available for use in parameters. This means that you can't, for example, declare sigilless named parameters and must instead explicitly use the is raw trait to get the rawness:

sub meow (\foo, :$bar is raw) {
    (foo, $bar) = ($bar, foo)
}
my $foo = 42;
my $bar = 100;
meow $foo, :$bar;
say [$foo, $bar]; # OUTPUT: «[100 42]»

The one other colonpair form available in parameters is the standard form that is used for aliasing multiple named params to the same name and parameter descructuring:

sub meow (:st(:nd(:rd(:$nth))), Positional :list(($, $second, |))) {
    say [$nth, $second];
}
meow :3rd, :list<a b c>; # OUTPUT: «[3 b]»

Pro-tip: if you're using the Rakudo compiler you may wish to take it easy with aliasing. Using aliases more than 1 level deep will cause the compiler to switch to the slow-path binder, which, as the name suggests, is about 10x slower.

A trick you can use is to use more than one parameter, each with aliases at most 1 level deep, and then merge them in the body:

sub meow (:st(:$nd is copy), :rd(:$nth)) {
    $nd //= $nth;
}

Argument Lists

Use of colonpairs in argument lists deserves a separate section due to a rule that's subtle enough to earn a spot in language's traps section. The rule involves the problem that a programmer may wish to pass Pair objects in argument lists as either a named or a positional argument.

In majority of cases, the colonpairs will be passed as named arguments:

sub args {
    say "Positional args are: @_.perl()";
    say "Named      args are: %_.perl()";
}

args :foo, :50bar, e => 42;
# OUTPUT:
# Positional args are: []
# Named      args are: {:bar(50), :e(42), :foo}

To pass a Pair object as a positional argument, you can do any of the following:

  1. Wrap the entire colonpair in parentheses
  2. Call some method on the colonpair, such as .self or .Pair; weird stuff like using R meta op on the => operator applies as well
  3. Quote the key in foo => bar syntax
  4. In foo => bar syntax, use a key that is not a valid identifier
  5. Put your Pairs in a list and slip it in with the | "operator"

Here's that list of options in code form:

my @pairs := :42foo, :70meow;
args :foo.Pair, (:50bar), "baz" => "ber", e R=> 42, 42 => 42, |@pairs;

# OUTPUT:
# Positional args are: [:foo, :bar(50), :baz("ber"),
#   42 => 2.718281828459045e0, 42 => 42, :foo(42), :meow(70)]
# Named      args are: {}

Number (3) is especially worth keeping in mind if you're coming from other languages, like Perl 5, that use the fat arrow (=>) for key/value separation. This construct gets passed as a named argument only if the key is unquoted and only if it's a valid identifier.

Should it happen that you have to use one of these constructs, yet wish to pass them as named arguments instead of positionals, simply wrap them in parentheses and use the | prefix to "slip" them in. For the list of Pairs we were already slipping in in previous example, you'll need to coerce it into a Capture object first, as Pairs stuffed into a Capture—unlike a list—end up being named parameters, when the Capture is slipped into the argument list:

my @pairs := :42foo, :70meow;
args |(:foo.Pair), |(:50bar),   |("baz" => "ber"),
     |(e R=> 42),  |(42 => 42), |@pairs.Capture;

# OUTPUT:
# Positional args are: []
# Named      args are: {"42" => 42, :bar(50),
#                      :baz("ber"), :foo(42), :meow(70)}

The same slipping trick can be used to provide named arguments conditionally:

sub foo (:$bar = 'the default') { say $bar }

my $bar;
foo |(:bar($_) with $bar);  # OUTPUT: «the default␤»
$bar = 42;
foo |(:bar($_) with $bar);  # OUTPUT: «42␤»

If $bar is not defined, the with statement modifier will return Empty, which when slipped with | will end up being empty, allowing the parameter to attain its default value. Since |(:) looks like a sideways ninja, I call this technique "ninja-ing the arg".

Auto-Quoting in => Form

The sharp-eyed in the audience might have noticed the e => 42 colonpair in the previous section used letter e as a key, yet in reversed form e R=> 42, the e became 2.718281828459045e0, because the core language has e defined as Euler's number.

The reason it remained a plain string e in the e => 42 form is because this construct auto-quotes keys that are valid identifiers and so they will always end up as strings, even if a constant, a sigilless variable, or a routine with the same name exists:

my \meows = '🐱';
sub ehh { rand }
say %(
    meows => 'moo',
    ehh   => 42,
    τ     => 'meow',
); # OUTPUT: «{ehh => 42, meows => moo, τ => meow}␤»

A multitude of ways exist to avoid this autoquoting behaviour, but I'll show you just one that's good enough: slap a pair of parentheses around the key:

my \meows = '🐱';
sub ehh { rand }
say %(
    (meows) => 'moo',
    (ehh)   => 42,
    (τ)     => 'meow',
);
# OUTPUT: «{0.58437052771857 => 42, 6.283185307179586 => meow,
#           🐱 => moo}␤»

Simple!

Conclusion

That's pretty much all there is to know about colonpairs. We learned they can be used to construct Pair objects, used as adverbs, and used to specify named arguments and parameters.

We learned about various shortcuts, such as using key only for boolean True, sticking the negation operator or an unsigned integer between the colon and the key to specify boolean False or an Int value. We also learned that parentheses can be omited on colonpair values if there's already a set of curly, square, or angle brackets around the value and that prepending a colon to a sigilled variable name will create a colonpair that will use the name of that variable as the key.

In the second half of the article, we went over available colonpair syntaxes when specifying named paramaters, the pecularities in passing colonpairs as either named or positional arguments, as well as how to avoid auto-quoting of the key by wrapping it in parentheses.

I hope you found this informative.

-Ofun

Perl 6 CaR TPF Grant: Monthly Report (June, 2018)

This document is the June, 2018 progress report for The Perl Foundation's Perl 6 Constant and Rationals Grant.


Tangibles

The bonus deliverable "Perl 6 Numerics" Language documentation page was merged to master. It describes all of the available Perl 6 numerics, their interactions, suitability, and hierarchy.

The bulk of work on constants also has been merged to post-release-2018.06 branch, which will be merged to master after this month's release. I wrote 200 spec tests, available in S04-declarations/constant-6.d.t spec file, and about 500 words of documentation to cover this work.

Rationals

Since my last report, I first continued working on Rationals, focusing on three pieces of work that currently reside in car-grant-unreduce branch

  1. Fixing the rare data race and doing some optimizations
  2. Fixing bad math in some ops with Zero-Denominator Rationals (ZDRs)
  3. Attempting a trial implementation where ZDRs are marked with a role, allowing us to improve performance of some operators.

The (1) was successful and I already was able to optimized some ops due to Rationals being always reduced now: == was made 28% faster and === was made 52% faster. I also made creation of Rationals 19% faster and argless Rational.round 4.7x faster (used by .Str and .base).

The plan for (2) was to try normalization to <1/0>, <0/0>, <-1/0> and the hope was that alone would fix all math problems. However, after that change some issues still remained. Also, doing this normalization created a new problem where code like say 42 / 0 would throw an Exception with message "division of 1 by 0 attempted" which is quite confusing for users who did not internalize that / op with Int objects is really just a Rat constructor. The 6.c spec actually covers this exact scenario and expects the thrown Exception to report value 42 for numerator, thus blocking this change.

The first attempt at (3) ended with a dead-end. Marking ZDRs with a role created an extra dispatch ambiguity with some operators like cmp. We already had to disambiguate that op with is default marker to disambiguate between Rational and Real candidates, so now we'd need an is default of defaults trait :). I gave up on this for now, but will likely revisit and try again.

As you can see, the Rationals work was a mixed bag, so to experiment with the problem space a bit I decided to implement my own rationals outside of core from scratch. The work is available in zoffixznet/perl6-Rashnl repo, which might become an ecosystem module if it offers significantly better rationals.

I doubt the entirety of Rashnl could be made core, as my current approach does not involve separate roles at all and just has a single class with a flag for fattiness that marks what in core is a FatRat type. The primary purpose of that work is to experiment with code and learn some lessons that could be applicable for core Rationals and achieve the goals of this Grant.

Due to that detour for the Rationals work and more time to think required, I switched to the work on constants for the time being…

Constants

The bulk of the work on constants is now completed and has been merged to post-release-2018.06 branch, which will be merged to master after this month's release.

I wrote 200 spec tests, available in S04-declarations/constant-6.d.t spec file, about 500 words of documentation, and 8 commits of the implementation.

Except for native types, the type constraints are now enforced on constants. The auto-coercive behaviour for %- sigilled constants was blocked by one test in 6.c specification and so that behavior has been added to 6.d language and currently requires the use of use v6.d.PREVIEW pragma to enable (6.c behavior is to simply throw without any attempts to coerce, making constant %foo = :42foo, :70bar fail, because it's a List).

One of the remaining things for constants is improving error reporting for unsupported constructs. Most likely I will implement support for coercers—even though they're currently not available on variables, there should be no problem with executing them during constant creation.

The other remaining item is natively-typed constants. Currently, my int const foo = 42 actually does not create a natively-typed constant at all. I hope the knowledge I'll gain while implementing the Grant's bonus work for support of native-typed unsigned attributes will help me in implementing the natively-typed constants as well.

No Report for July / Further Work

As has been discussed with and approved by my grant manager, I plan to now take a month off working on this grant, so there will be no report in mid-July, and the next report will be in mid-August. I plan to take this time to work on resolving Rakudo's outstanding spectest issues on Windows and possibly resolving some of the open Issues with our community websites.

After that period, I will resume working on the grant, finishing the remaining work on constants, and then going back to Rationals, and finally finishing the bonus work with the natively-typed entities.

A Call to Action: Polish Perl 6 First Steps Experience

Read this article on Rakudo.Party

If you follow the updates on KickStarter, you may know the Learning Perl 6 book is nearing completion, with the author planning to submit final manuscript to O'Reilly on June 18th.

What this means is the July's Rakudo Star release will possibly be the release the first crop of readers of that book will be using (the next release after that is in October). I've seen several people say they're waiting for this book to get published before they give Perl 6 a try. Coupled with the marketing the author and O'Reilly will be doing for the book, I expect to see an influx of new users.

For that reason, I'm making a call to action, for everyone to polish the experience of the first steps those users will make in Perl 6.

How to Help?

There are several things you can help with, depending on your skillset. And before anyone protests, don't worry, there's one thing everyone is able to do…

Install Perl 6

The easiest thing you can do is grab a clean box and try to install Perl 6 to it. This is especially useful if you've never done it before and have no idea what you're doing, as it'll be very easy for you to see things that need to be improved.

Are you having trouble finding or choosing what to install? Getting installation errors? Having trouble finding support channels? Report it!

Unless you can think of a better place, you can always report these things in our User Experience repo by filing a new Issue.

Learn/Use Perl 6

This, again, is the area where the less experience with Perl 6 you have, the better. Is there something you find difficult to use or hard to find? Let us know.

Code editors, books, documentation, modules, tutorials, excercises, contests, language news, support channels. If you were looking for any of those things and had a hard time finding them, the process will likely need to be addressed.

Rakudo on Windows

This is the area where I hope we'll make a lot of progress before the next Rakudo Star release (it'll be in July, based on Rakudo compiler release scheduled for July 21st). Few, if any of the core devs use Windows as their development environment, so the state of Rakudo on Windows is slightly lagging behind.

While 6.d-proposals roast stresstest is clean on Linux and MacOS, on Windows, there's a bunch of test failures. Several of them are likely problematic tests themselves (e.g. those that shell out and expect cmd.exe to handle Unicode out of the box). When I last looked at the failing tests, some of them were failing due to how &run escapes arguments; since perl6 is launched with a batch file on windows, using $*EXECUTABLE with &run would require using cmd.exe-style escapes of command line arguments, which &run doesn't use. There's some discussion for this issue on R#1325, RT#132258, and self-rejected RFC R#1306.

If you'd like to look into these problems, you can install Rakudo from source on Windows and then run gmake stresstest (or whatever make equivalent you have) to clone all the spectests into t/spec directory and run them, so you'll be able to see what's failing. You can run individual tests with t/fudgeandrun t/spec/42-foobar/the-test-file.t

There's also a second item of lesser importance: Rakudo Star build on 32-bit Windows. The latest build we have for that system is 2016.01, which is quite outdated. On occasion people do ask for 32-bit builds and currently we can only suggests to build from source.

It'd be nice to have a more recent build created. I'm unfamiliar with what's involved. If you're interested in helping. Join our IRC chat and try to speak to stmuk or FROGGS

Help Resolve Issues

Help us resolve open Issues. In the context of this call to action, the most pertinent repos would likely be User Experience, Perl6.org website, Modules.Perl6.org website, as well as Docs, Rakudo Star, Rakudo itself, and Roast Test Suite.

For core hacking resources, there are some tutorials with "Core Hacking" in their titles on Rakudo.Party website and the NQP/Rakudo Internals Course and 6guts blog. I also like to use Z-Script rakudo dev helper script.

Conclusion

The LP6 book is about to hit the shelves and will likely bring a crop of new Perl 6 users. We can improve the perception of the language by polishing the experience of those users. Let's see if there are any problems with obtaining the compiler or any resources a begginer would need to get started with the language.

There are also some issues on Windows that need to be addressed, such as failing stresstests and 32-bit Rakudo Star builds.

If you can give a hand with any of that, it'd be greatly appreciated. File a new Issue in our User Experience repo or just chat with us on IRC.

-Ofun

Perl 6 CaR TPF Grant: Monthly Report (May, 2018)

This document is the May, 2018 progress report for The Perl Foundation's Perl 6 Constant and Rationals Grant.


Tangibles Produced

This month I was working in docs and roast repos, in separate car-grant-midrat branches. So far, they contain 29 documentation commits and 11 spec commits adding about 5,824 words of documentation and 152 tests.

The tests specced the MidRat type. The documentation, along with documenting MidRat/MidRatStr types, centered largely around new Language/Numerics page that describes all of the available Perl 6 numeric types—including native and atomic numerics—their purpose, properties, and hierarchy. This guide was not on the list of deliverables of the Grant and has been produced as a bonus item.

General Info

I started the grant by working on adding the proposed MidRat/MidRatStr type pair. This was the most contentious part of the Rationals Work Proposal that before the grant underwent three revisions, settling on solving the problem by adding the MidRat type.

I went full-on with Test/Documentation Driven Development and I think the result is a fantastic example of the power of this approach. After adding 5,824 words of docs and 152 tests, I still haven't written a single line of code of the implementation in the compiler itself.

The process highlighted several issues with MidRat type and I've tentatively decided not to implement it at this time. Its functionality will be subsumed with the plain Rat type. The plan to change Rat type to use uint64 native type for the denominator is tentatively canceled and instead an Int denominator will accept denominators over 64 bits in size in all the cases where a MidRat type were going to be produced. At the same time, the Rat will degrade to a Num in all the cases where a MidRat were to do so.

Doing so robs us of potential performance improvements due to using native denominator, however we still have the option of implementing a MidRat-type solution open in the future. Were we to go with implementing MidRat right now, we'd be locking ourselves into supporting it basically forever, and exposing ourselves to yet unforeseen design issues.

Issues/Clarifications of MidRat

What is a .Numeric/.Real of a MidRat?

Writing documentation first showed an ambiguity with what .Numeric/.Real methods should return for a MidRat. The work proposal had MidRat as an allomorph of Rat and FatRat, and while .Numeric on IntStr allomorph returns its numeric component, a MidRat would have two such components.

This issue is complicated by the fact that prefix:<+> uses .Numeric, so that means 0 + MidRat.new(1,2) would produce a Rat objet, yet +MidRat.new(1,2) would produce a potentially different object. To maintain consistency there, at the time I settled on simply having .Numeric/.Real coerce the MidRat to a Rat, which means that had the potential of degradation of that Rat to a Num. Bring the MidRatStr into play and you get three different types by chaining .Numeric calls. That was already slightly weird.

Convergence to Plain Rat

While documenting infectiousness of numerics, the question of infectiousness of MidRat came about. The original work proposal was vague in this area but after documenting the MidRat type, it became obvious that its infectiousness must be the same as if Rat type was used instead. That's the first point of convergence to Rat.

The second became apparent when writing degradation tests. The work proposal argued for MidRat to be an allomorph of Rat and FatRat types. A MidRat has infectiousness of a Rat. But that means this code…

my FatRat $a = get-rational;
my FatRat $b = get-rational;
say $a + $b;

…has the potential to produce a Num of all things (MidRats degrade to Rat and that can degrade to a Num). That's certainly unacceptable, so by this point, I decided to toss FatRat from the ancestors of MidRat, leaving it be just a subclass of Rat. This largely resolved the issue of what to return from .Numeric/.Real methods.

...

By now you can see that the MidRat got reduced to just being a Rat with non-native denominator. Adding two extra types (MidRat/MidRatStr) to an already populous zoo of Perl 6 numerics for such a tiny detail was hard for me to justify. So, after flipping a coin to confirm my gut feeling, I decided to abandon the idea of MidRat and to repurpose the Rat type to resolve all of the issues MidRat were meant to resolve.

The documentation and tests I wrote won't go to waste: they're simply going to be modified to document/test the MidRat's functionally from the point of view of the Rat type that subsumed it.

Going Forward

I still plan on doing the Bonus Work of the grant, fixing bugs in native uint64 attributes, despite no longer planning to use them directly in the denominator of the Rat type. I'll also try to make a perf improvement by selecting native/non-native NQP ops for dividing Rats, to make up for not using native attributes in them.

In lieu of implementing the MidRat type originally promised, I'll work on resolving some additional bugs. Likely trying to resolve value drift in MoarVM Numification of Rationals that currently does not select the closest representable Num.

For the next month, I plan to work more on Rationals, fixing the data race and normalization of zero-denominator Rationals.

Related Work Done By Others

  • AlexDaniel++ fixed object-identity bug in Rationals. The fix was done using the .REDUCE-ME method, which has the data race and will go away in about a month, but in the meantime, object identity will be correct.
  • thundergnat++ did some work on improving performance of Rat.Str and FatRat.Str and fixed an issue with unwanted trailing zeros.

WANTED: Perl 6 Historical Items

Read this article on Rakudo.Party

The Perl 6 programming language had a turbulent birth. It was announced in the summer of 2000 and the first stable language release shipped out only 2 years ago, on Christmas, 2015. A lot has happened during that decade and a half, yet the details are hard to piece together.

After my recent facelift to rakudo.org, I'm working on a (second) facelift to perl6.org website.

Part of the work involves bringing all the Perl 6 deliverables under one umbrella, so the user isn't thrown around multiple websites, trying to find what to install. At the same time, we want to strengthen the distinction between Perl 6 the language and the compilers that implement it, as well as encourage more implementors to give it a go at implementing a Perl 6 programming language compiler.

The Perl 6 Programming Language Museum will be part of that effort and along with interesting tidbits of Perl 6 history, it'll showcase past implementation attempts that may no longer be in active development today. Since I don't know much about what happened before I came to the language sometime in 2015, I need your help in collecting those tidbits.

Larry Wall at FOSDEM 2015, photo by Klapi

In my mind's eye, I'm imagining a few pages on perl6.org; something in the same vein as Computer History Museum's pages—pictures, years, and info, and potentially links to code repositories. Depending on the content we collect, it's possible there will be a digital PDF version of the Museum that can also be printed and handed out at events, if desired.

I'm looking for:

  • Descriptions of interesting/significant events (like the mug throwing incident).
  • Descriptions of interesting/significant implementations of Perl 6 or influential Perl 6 projects. Having links to repos/tarballs of their code is a plus.
  • Samples of interesting/significant email threads or chat logs.
  • Pictures of interesting/significant objects (first sight at plush Camelias?).
  • Pictures of interesting/significant humans (a filled out model release form is required).
  • Anything else that's Museum worthy.

If you have any of these items, please submit them to the appropriate year directory in the Perl 6 Museum Items repository. If you're a member of Perl 6 GitHub org, you should already have a commit bit to that repo. Otherwise, submit your items via a pull request.

Let's build something cool and interesting for the people using Perl 6 a hundred years from now to look at and remember!

If you have any questions or need help, talk to a human on our IRC chat.

-OFun