Stories
Slash Boxes
Comments
NOTE: use Perl; is on undef hiatus. You can read content, but you can't post it. More info will be forthcoming forthcomingly.

All the Perl that's Practical to Extract and Report

use Perl Log In

Log In

[ Create a new account ]

masak (6289)

masak
  (email not shown publicly)
http://masak.org/carl

Been programming Perl since 2001. Found Perl 6 somewhere around 2004, and fell in love. Now developing November (a Perl 6 wiki), Druid (a Perl 6 board game), pls (a Perl 6 project installer), GGE (a regex engine), and Yapsi (a Perl 6 implementation). Heavy user of and irregular committer to Rakudo.

Journal of masak (6289)

Monday September 06, 2010
01:30 AM

The Pugs repository is dead; long live Mu!

This weekend marks the end of a quite astonishing era. The Pugs repo, that hosted all the amazing Perl 6 activity, is no more. At its height, this repository had 242 committers! I just checked.

The Pugs repository has functioned as a common writing area for Perl 6-related things. First Pugs; then a lot of external modules and scripts written in Perl 6; what would eventually morph into the Perl 6 test suite; even the Perl 6 specification and the standard grammar. Commit bits (write access credentials) were handed out liberally, and newcomers were encouraged to help improve things they found amiss. The degree to which this system worked without a hitch has been quite astonishing. There have been no edit wars, no vandalism, no banning. Just the continuing flow of commits. Trust the anarchy.

So why are we killing off the Pugs repository? Well, technologies come and go; not so much because they worsen by each year, but because our expectations rise in a sort of software inflation. The SVN repository became too high-maintenance, and a transition to git was the natural next step. The Pugs repository has been split up into the git repositories linked to in the previous paragraph. Those bits that don't belong in any of the standard bins remain in the Mu repository. (Its name is a reference to the most-general object type in Perl 6, what in other languages is commonly known as 'Object'.)

I for one salute our new git-based overlords! May the commits keep flowing even under this new system. Also, moritz++ for carrying out the move.

Wednesday September 01, 2010
05:31 PM

Yapsi 2010.09 Released!

It is with a peevish exultation of spirit that I announce on behalf of the Yapsi development team the September 2010 release of Yapsi -- soon to be a major motion picture -- a Perl 6 compiler written in Perl 6.

You can download it here (or, if you happen to be on an avian-carrier-based network, you can "pidgeon" it here).

Yapsi is implemented in Perl 6. It thus requires a Perl 6 implementation to build and run. This release of Yapsi has been confirmed to work on both Rakudo Star 2010.08 and Rakudo Star 2010.07.

Yapsi is an "official and complete" implementation of Perl 6. Yapsi's official status has been publicly confirmed by Patrick Michaud, the Rakudo pumking. The claim about Yapsi being complete... well, it might just be what PR people sometimes refer to as "a slight exaggeration". On the bright side, it's becoming less so with each new release.

This month's release brings you unless and until, as well as our-scoped variables:

$ yapsi -e 'my $a = 0; unless $a { say 42 }'
42

$ yapsi -e 'my $a = 0; until $a { say ++$a }' 1

$ yapsi -e 'our $a = 42; { my $a = 5; { say our $a } }' 42

For a complete list of changes, see doc/ChangeLog.

Quite a lot of features are within reach of people who are interested in hacking on Yapsi. See the doc/LOLHALP file for a list of 'em. In fact, that's how isBEKaml++ implemented 'unless' this month. (After which he exclaimed "that was easy!" and tackled 'until'.) If you're wondering whether you're qualified to help with the Yapsi project, that probably means you are.

Yapsi consists of a compiler and a runtime. The compiler generates instruction code which the runtime then interprets. In Yapsi, that instruction code (unfortunately) is called SIC[!]. Until further notice, SIC as a format changes with each monthly release for various, mostly good reasons. However, if you write a downstream tool that makes assumptions about the SIC format, someone might change it just out of spite. SIC is explicitly not compatible with later, earlier, or present versions of itself.

An overarching goal for making a Perl 6 compiler-and-runtime is to use it as a server for various other projects, which will hook in at different steps:

  • A time-traveling debugger (tardis), which hooks into the runtime.
  • A coverage tool (lid), which will also hook into the runtime.
  • A syntax checker (sigmund), which will use output from the parser.

Another overarching goal is to optimize for fun while learning about parsers, compilers, and runtimes.

Have the appropriate amount of fun!

Thursday August 26, 2010
07:22 PM

Idiomatic Perl 6

So, I wrote a program to generate Pascal's triangle. The first ten rows of the triangle, at least. It only used simple features of Perl 6, such as scalars, nested arrays, and for loops.

my $ELEMENTS = 10;
my @pascal = [1];

for 1 .. $ELEMENTS - 1 {
    my @last = @pascal[ * - 1 ].list;

    my @current;
    push @current, @last[0];
    for 0 .. @last - 2 {
        push @current, @last[$_] + @last[$_ + 1];
    }
    push @current, @last[ * - 1 ];

    push @pascal, [@current];
}

say @pascal.perl;

In fact, save for simple mechanically substitutable differences, it could have been a Perl 5 script. In fact, with a bit of manual array allocation, it could have been a C script. That's OK; there's a tolerance in the Perl community of writing code that looks like it was thunk in some other language.

But I've heard that Perl 6 is great at doing things with operators. For example, the Z operator, which interleaves two lists, seems to be able to help me write my push statements more succinctly:

my $ELEMENTS = 10;
my @pascal = [1];

for 1 .. $ELEMENTS - 1 {
    my @last = @pascal[ * - 1 ].list;

    my @current;
    for (0, @last) Z (@last, 0) -> $left, $right {
        push @current, $left + $right;
    }


    push @pascal, [@current];
}

say @pascal.perl;

The parentheses before and after the infix:<Z> aren't necessary, because the Z operator has looser precedence than comma. They're just shown here to make your eyes accustomed to reading this construct.

In fact, now that only the addition is performed in the inner loop, I might as well use the Z+ operator, which does this for me.

my $ELEMENTS = 10;
my @pascal = [1];

for 1 .. $ELEMENTS - 1 {
    my @last = @pascal[ * - 1 ].list;

    my @current = 0, @last Z+ @last, 0;

    push @pascal, [@current];
}

say @pascal.perl;

Now as the remaining loop shrinks to a size I can take in all at once, I see a bit more clearly what I'm doing: I'm building each new list from the previous one. I could feed the previous list into a named function to get the current one:

my $ELEMENTS = 10;
my @pascal = [1];

sub next-list(@p) {
    [0, @p Z+ @p, 0]
}

for 1 .. $ELEMENTS - 1 {
    my @last = @pascal[ * - 1 ].list;

    my @current = next-list(@last);

    push @pascal, @current;
}

say @pascal.perl;

Or I could just feed it into a in-place anonymous sub.

my $ELEMENTS = 10;
my @pascal = [1];

for 1 .. $ELEMENTS - 1 {
    my @last = @pascal[ * - 1 ].list;

    push @pascal, (sub (@p) { [0, @p Z+ @p, 0] }).(@last);
}

say @pascal.perl;

But why even a sub? Perl 6 has a lighter construct, namely a "pointy block" (also known as a "closure" or a "lambda"). It doesn't participate in the call stack, and it's slightly easier to write.

my $ELEMENTS = 10;
my @pascal = [1];

for 1 .. $ELEMENTS - 1 {
    my @last = @pascal[ * - 1 ].list;

    push @pascal, (-> @p { [0, @p Z+ @p, 0] }).(@last);
}

say @pascal.perl;

Let's look at what the code does. Seed with one element. Calculate the next element based on the previous one. Stop at some point.

But that's exactly what the series operator does. The one that's written with three dots. We have a starting value, a way to get from one value to the next (our code block above), and a stopping value.

Well actually, we don't have the stopping value. But that's OK, since the series operator is lazy. So if we only request the first 10 values, it won't loop forever giving us the rest of the list.

my @pascal := do [1], -> @p { [0, @p Z+ @p, 0] } ... *;

say @pascal[^10].perl;

(The extra do required because of a shortcoming in Rakudo.)

Now. Something very much like this code was posted first on Rosetta code and then on Moritz' blog. (TimToady used a sub, but said later that he'd have preferred binding.)

A couple of Perl 5 people's reactions were — somewhat uncharacteristically — of a negative flavour, similar to how people seem to react to the periodic table of operators:

@shadowcat_mst: an excellent example of why I consider camelia perl to be a language research project more than a production language

@pedromelo: I'm seriously considering this post as an example of what I don't want Perl6 to become...

I think these reactions are mainly feature shock. Higher-order operators, pointy blocks, and the series operator... they're all good, well-established features, which find daily use in Perl 6 programs. Maybe using them all together like that flung some people off the deep end. Never mind that the resulting script is all essential complexity, with virtually no boilerplate from the original script left.

This is the first time that's happened. I think it's important to listen to what Perl 5 people think and to try to respond to that. But I also think that this time, it's a case of them seeing some highly idiomatic Perl 6, and freaking out a bit.

And I think that that, in some odd sense, is a good thing. Well, not freaking people out, per se. But the fact that we did shows that there's something forming which might be tentatively called "idiomatic Perl 6": people on the inside can read it quite easily, but those on the outside, even Perl 5 folks looking in, instinctively go "eeeeew!".

That's OK. You're not meant to start with the idiomatic stuff. Language acquisition takes place step by step, and that goes for learning Perl 6 as well. On the way there, just don't confuse distaste with lack of familiarity.

Sunday August 22, 2010
04:39 PM

Where in the world is the package lexpad?

(This post isn't very punny. For those of you who need puns to survive, try to figure out why jnthn++ named the IRC logs "the hottest footwear" recently. The answer, as with all good puns, is highly unsatisfying.)

My quest for a Perl 6 implementation takes me ever deeper into the esoterics of lexpads, runtimes, and a far-more-than-everything-you-needed-to-know mindset. Today some random firings in my brain turned into the following conversation on #perl6.

During the conversation, I proposed two theories, both of which turned out to be wrong. (pmichaud++ shone the necessary light both times.) Being wrong felt less important than getting my mental model fixed.

I first thought of presenting the results of the below conversation as a simple tutorial ("How our declarations work. The complete guide."), but now I think that the conversation, minimally edited, manages to be such a tutorial on its own.

Besides, blogging things in their raw and undigested form is a sign of the times. Enjoy!

<masak> I have a question. is there a need for a special "package lexpad" containing 'our'-declared variables, or can the package lexpad simply be equated to the topmost lexpad in the package?

<masak> my suspicion is the latter, but I might be missing something.

<pmichaud> the package lexpad can't be the same as the top most lexical

<pmichaud> module XYZ { my sub abc() { ... } }; # abc should not appear in the package

<masak> oh!

<masak> right.

<masak> so, separate one, then.

<jnthn> Additionally, lexpads are meant to be static by the time we hit runtime, and you're allowed to shove stuff into the package dynamically. Not quite sure how those two hold together.

<pmichaud> well, module XYZ { ... } creates a lexical XYZ entry that holds the package entries

<jnthn> Aha!

<pmichaud> and it's just a hash, really.

<masak> does inserting the package lexpad below the outside lexpad (and above the topmost lexpad) make sense? that way, Yapsi wouldn't need any special opcodes for doing 'our'-variable lookups.

<pmichaud> the package lexpad is an entry in the outside lexpad, yes.

<pmichaud> I'm not sure it encapsulates the nested lexpad, though.

<masak> hm.

<masak> if it doesn't, I don't really see how it's visible from inside the package.

<masak> I've more or less convinced myself that sandwiching it between outer and topmost is what I want to do for Yapsi.

<pmichaud> our &xyz can make an entry in both the package and in the lexical.

<pmichaud> this is what rakudo does now.

<pmichaud> we have to do similar things for methods already, too.

<masak> sure. it makes entries in both.

<pmichaud> by having entries in both, that's how it's visible inside the package

<masak> hm, indeed.

<masak> no need to have the package lexpad visible from inside.

<pmichaud> anyway, sandwiching might work too. haven't quite gotten to that point in Rakudo thinking yet. And it can get a bit tricky with multis.

<masak> no need to sandwich it in, either. it can sit in limbo outside the tree of scopes.

<pmichaud> oh, I know why it perhaps shouldn't (or should) be visible:

<pmichaud> my $x = 'lexical'; module XYZ { say $x; { our $x = 'package'; } }

<masak> ...yes?

<pmichaud> I'm pretty sure "say $x" needs to grab the 'lexical' $x, not the one that might be "sandwiched" in a package.

<masak> of course.

<masak> that falls out from ordinary scope nesting and shadowing.

<masak> innermost block binds its lexical to the container in the package lexpad.

<masak> so, that speaks out against sandwiching.

<masak> pmichaud++

So there you go. There's a separate package scope, and it isn't sandwiched.

(Answer: The missing link is the "IR clogs" meme from #parrot. I can hear you groaning... I did warn you.)

Friday August 13, 2010
05:35 PM

Weeks 8..12 of GSoC work on Buf -- not packing it in yet

I was reproached by my colleague because of the lack of "no cake"-style jokes in this last grant update. So what can I do to amend the situation? Firstly, let me concede that the below blog post is almost tear-inducingly boring. Secondly, let me remind you that when accosted by boring material such as that in this post, the most important thing to have is a positive outlook on life. Thank you.

The past couple of days have been really eventful. The coming couple of days probably will be, too. It seems fitting to punctuate all this eventfulness with a status-updating blog post, something that I apparently haven't gotten around to in a few weeks.

So, what's been happening?

  • In the last update, I was at a point where I needed to encode to different encodings, not just UTF-8. Tonight I had an enlightening discussion with the Parrot people, which gave all the pieces of the puzzle. Now it's just a Simple Matter of Programming. More precisely, I need to apply it to this spot in the code base.
  • By that discussion, I was once again made aware that Parrot differs between encodings and charsets. For example, utf8 is an encoding, but iso-8859-1 is a charset. It's confusing me slightly, but that's OK. I can make the code work so that both are treated as "encodings" on the Perl 6 level.
  • I got unexpected assistance from oha++, who took me aside in private discussions to discuss new wild ideas for Buf. It all culminated in a p6l thread. Oha is writing code that uses Buf for network traffic, and has been preparing a patch for making IO::Socket::INET return Bufs instead of Strs. In trying out this patch, oha++ found that some tests will never work when Bufs are used. Those tests will probably need to be rewritten.
  • During the past week or so, I've been implementing pack and unpack in a branch. I'm making steady progress, and trying to take in documentation such as Perl 5's perldoc -f pack and perlpacktut and Erlang's ei and Tcl's binary . It's a lot to take in, and I won't aim for full functionality — look, Perl 5 has 14699 tests for pack! — but rather a reasonable subset of the directives from Perl 5.

There's a lot to be said about the interplay between Perl 6's high level of abstraction and the almost reckless to-the-metal feeling of &pack/&unpack. Add to this that the "metal" in this case is Parrot, which in some regards is there to abstract away the real metal. I think the details of this interplay might well be the subject of a separate blog post. When I'm not busy finishing up the code itself. 哈哈

The hard pencils-down deadline for GSoC is on Monday. I'm pretty sure I will have tied up the remaining loose ends by then, but I also foresee a couple of fairly focused hours programming before that. Time to dig back in; see you on the other side.

Tuesday August 10, 2010
03:22 PM

There's just no way to keep up with all you people

Let's look at a week two years ago in the perl6 RT queue. Who submitted bugs?

Moritz
Moritz
Moritz
Moritz
Yaakov
Yaakov
Carl
Moritz
Moritz
Ron
Charlie
Carl
Carl
Carl
Carl
Carl

Seems I just managed to tie with Moritz++ there. Almost one ticket a day sounds about right from what I remember of my submit pace from that time. In total, there were 16 tickets in that week.

Ok, that was two years ago. What about one year ago? By this time, Rakudo had already picked up a bit of a reputation.

Patrick
Patrick
Carl
Alex
Alex
Timothy
Moritz
Gilbert
Carl
Timothy
Timothy
Eduardo
Carl
Carl
Carl
dakkar
dakkar
Hanno
Solomon
Ben
Solomon
Ben
dakkar
Aaron
Solomon

Dang, only five tickets that week. 哈哈

Still, a pretty typical week. 25 tickets all in all. We see a bit more variation in the names now. That's the new people.

Finally, let's look at last week:

Ekkehard
Timothy
Tom
cognominal
Cosimo
Sven
Chris
Carl
Carl
Carl
Moritz
Simon
Mulander
Carl
Carl
Paweł
Tadeusz
Aaron
cognominal
cognominal
Carl
Paweł
Lithos
Lithos
Carl
Carl
Tyler
Alex
Lithos
Moritz
Lithos
Brian
Moritz
Moritz
Paweł
Steve
Francesco
Lithos
Jarrod
Lithos
Francesco
Carl
Moritz

These figures help express what I feel. I'm still submitting a fair amount of tickets — all of nine last week — and still they make up an ever-smaller proportion of the growing deluge of perl6 tickets on RT.

Or, put differently, all you other people finally caught up with me. I can no longer compete with the rest of you. 哈哈

It makes me proud and excited to disappear under the waves of other people's contributions. There's been both a slow buildup over the past two years, and a sudden spike thanks to Rakudo Star. Together, they help drown out my insistent, repeating splashes on RT.

Rakudobugs are love. There's a whole lotta love out there right now. ♥ This uptake is what we've been waiting for.

Wednesday August 04, 2010
06:10 PM

Perl 6 and Perl 5 are different languages

Today at the YAPC::EU keynote, the inimitable Larry Wall, accompanied by his guardian angel and his guardian devil, made a poll asking which ones in the audience believed Perl 5 and Perl 6 are the same language, and which ones believed they are two different languages.

I was in the front row, so I didn't see the sea of hands and which way the poll tipped. But on my row, both Patrick Michaud and Jonathan Worthington voted "different". I was slightly surprised to find myself voting "different" as well. I'm the one who only last year wrote this entry which seems to insist on a "same" vote, if only by criticizing those who take the opposite view.

I think that what's happened in the past year is that there's a bit more room in the "Perl" space. We're now talking of two different languages in the Perl family, and the Perl community being shaped like a tuning-fork with its Perl-5 people, Perl-6 people, and Perl-omnivore people. It simply feels safer now to state "different", in a way it didn't last year.

One thing about the tuning fork that I really like is that it's basically two universes in one. We could've had

(a) Perl 6 taking off early and essentially killing Perl 5, precluding its renaissance as Modern Perl, or
(b) Perl 6 floundering so badly and for so long that Perl 5 took over with such force that no-one bothered to develop Perl 6 anymore, and a "Forever Five" condition in the community was announced.

Instead we find ourselves in a junctional universe where both languages are thriving and evolving. And they're different, not least because Perl 5 is older, more mature, and more used in business-oriented environments. But Perl 6 is getting there too, and the two languages will start playing together on increasingly equal footing, just like half-a-generation-apart siblings would.

I like that.

Sunday August 01, 2010
06:50 PM

Yapsi 2010.08 Released!

It is with vertiginous modesty that I want to announce, on behalf of the Yapsi development team, the August 2010 release of Yapsi, a Perl 6 compiler written in Perl 6. (Am I using, too many, commas?)

You can get it here — as a bonus, if you download within 24 hours, the bits in your download will be hand-painted and signed by nine indefatigable mice from northern Belarus.

Yapsi is implemented in Perl 6. It thus requires a Perl 6 implementation to build and run. Both Rakudo Star and the latest monthly release ("Atlanta") seem to be fit to the task.

Yapsi is an "official and complete" implementation of Perl 6. It's official because we stole the "Official Perl 6" rubber stamp and applied it liberally. Unfortunately, we also used all the special ink -- please don't tell any of the other implementors that. It's complete because we implemented all the parts of the synopses that weren't eaten by the team's pet dugong.

This month's release consists of a total refactor of both the runtime and the compiler. The Yapsi.pm file is about 100 lines shorter, with the same functionality. Lexical variables are now handled more correctly. For a complete list of changes, see doc/ChangeLog.

Quite a lot of features are within reach of people who are interested in hacking on Yapsi. See the doc/LOLHALP file for a list of 'em.

Yapsi consists of a compiler and a runtime. The compiler generates a so-called instruction code, which is a code of instructions, for the runtime to run. This is fairly common, and nothing to be agitated about. The instruction code is called SIC, which is probably slightly less common. SIC is extended, re-thought and eaten by the team's pet dugong on a regular basis, so don't expect SIC from one release to be runnable on another.

An overarching goal for making a Perl 6 compiler-and-runtime is to use it as a server for various other projects, which will hook in at different steps:

  • A time-traveling debugger (tardis), which hooks into the runtime.
  • A coverage tool (lid), which will also hook into the runtime.
  • A syntax checker (sigmund), which will use output from the parser.

Another overarching goal is to optimize for fun while learning about parsers, compilers, and runtimes.

Gotta go feed S16 to the team's pet dugong. We wish you the appropriate amount of fun!

Thursday July 22, 2010
08:24 PM

6 built-ins in Perl 6 that you never knew you needed

.pick

say @deck.pick();                   # pick a card, any card...

say @deck.pick(5);                  # poker hand

my @shuffled = @deck.pick(*);       # here, '*' means 'keep going'

my @urn = <black white white>;      # beads, 1/3 black, 2/3 white
.say for @urn.pick(50, :replace);   # put back after each pick

for @urn.pick(*, :replace) {
    .say;                           # infinite bead picker
}

say [+] (1..6).pick(4, :replace);   # 4d6

class Enemy {
    method attack-with-arrows   { say "peow peow peow" }
    method attack-with-swords   { say "swish cling clang" }
    method attack-with-fireball { say "sssSSS fwoooof" }
    method attack-with-camelia  { say "flap flap RAWWR!" }
}

my $selector = { .name ~~ /^ 'attack-with-' / };
given Enemy.new -> $e {
    my $attack-strategy
        = $e.^methods().grep($selector).pick();

    $e.$attack-strategy();           # call a random method
}

.classify

my @names = <Patrick Jonathan Larry Moritz Audrey>;
say .key, "\t", ~.values
    for @names.classify( *.chars );

# Output:
# 5       Larry
# 6       Moritz Audrey
# 7       Patrick
# 8       Jonathan

.say for slurp("README")\            # whole file into string
         .words()\                   # split into list of words
         .classify( *.Str )\         # group words w/ multiplicity
         .map({; .key => .value.elems })\
                                     # turn lists into lengths
         .sort( { -.value } )\       # sort descending
         .[ ^10 ];                   # 10 most common words

class Student {
    has Str $.name;
    has Int $.grade is rw;
}

my Student @students = get-students();
for @students.classify( *.grade ).sort -> $group {
    say "These students got grade $group.key():";
    say .name for $group.value.list;
}

.sort

# 1 if $a is higher, -1 if $b is higher, 0 if equal
$a <=> $b;

# sort students according to grade
@students.sort: -> $a, $b { $a.grade <=> $b.grade };

# same thing
@students.sort: { $^a.grade <=> $^b.grade };

# same thing
@students.sort: { .grade };

# same thing
@students.sort: *.grade;

# leg gives -1, 0 or 1 according to lexicographic ordering
# 'leg' is for Str, 'cmp' is now for type-agnostic sort
$a leg $b;

# sort students by name (Unicode order)
@students.sort: { $^a.name leg $^b.name };

# same thing
@students.sort: *.name;

# don't worry, things are properly cached; no re-evaluations
@items.sort: *.expensive-calculation();

# ...which means this works (and is a fair shuffle)
@deck.sort: { rand }

# ...but this is cuter :)
@deck.pick(*);

Operator overloading

sub infix:<±>($number, $fuzz) {
    $number - $fuzz + rand * 2 * $fuzz;
}

say 15 ± 5;                          # somewhere between 10 and 20

sub postfix:<!>($n) { [*] 1..$n }
say 5!;                              # 120

class Physical::Unit {
    has Int $.kg = 0;                # these attrs denote powers of units
    has Int $.m  = 0;                # eg $.kg == 2 means that this object
    has Int $.s  = 0;                # has a kg**2 unit

    has Numeric $.payload;

    method multiply(Physical::Unit $other) {
        Physical::Unit.new(
            :kg( $.kg + $other.kg ),
            :m( $.m + $other.m ),
            :s( $.s + $other.s ),
            :payload( $.payload * $other.payload )
        )
    }

    method invert() {
        Physical::Unit.new(
            :kg( -$.kg ), :m( -$.m ), :s( -$.s ),
            :payload( 1 / $.payload )
        )
    }

    method Str {
        $.payload
        ~ ($.kg ?? ($.kg == 1 ?? " kg" !! "kg**$.kg") !! "")
        ~ ($.m  ?? ($.m  == 1 ?? " m"  !! "m**$.m")   !! "")
        ~ ($.s  ?? ($.s  == 1 ?? " s"  !! "s**$.s")   !! "")
    }
}

sub postfix:<kg>(Numeric $payload) { Physical::Unit.new( :kg(1), :$payload ) }
sub postfix:<m>(Numeric $payload) { Physical::Unit.new( :m(1), :$payload ) }
sub postfix:<s>(Numeric $payload) { Physical::Unit.new( :s(1), :$payload ) }

# Note how we now use 'multi sub', so as not to shadow the original infix:<*>
multi sub infix:<*>(Physical::Unit $a, $b) {
    $a.clone( :payload($a.payload * $b) );
}

multi sub infix:<*>($a, Physical::Unit $b) {
    $b.clone( :payload($a * $b.payload) );
}

multi sub infix:<*>(Physical::Unit $a, Physical::Unit $b) {
    $a.multiply($b);
}

multi sub infix:</>(Physical::Unit $a, $b) {
    $a.clone( :payload($a.payload / $b) );
}

multi sub infix:</>($a, Physical::Unit $b) {
    $b.invert.clone( :payload($a / $b.payload) );
}

multi sub infix:</>(Physical::Unit $a, Physical::Unit $b) {
    $a.multiply($b.invert);
}

say 5m / 2s;                         # 2.5 m s**-1
say 100kg * 2m / 5s;                 # 40 kg m s**-1

infix:<Z>

# Z (the 'zip operator') means "mix these lists together"
my @tastes = <spicy sweet bland>;
my @foods = <soup potatoes tofu>;
@tastes Z @foods; # <spicy soup sweet potatoes bland tofu>

# » means "call the method for each element"
.say for @students».grade;                 # all the grades

for @students».name Z @students».grade -> $name, $grade {
    say "$name got a $grade this year";
}

# Note that the latter list is infinite -- it works anyway
for @students».name Z (1..6).pick(*, :replace) -> $name, $roll {
    say "$name rolls a $roll";
}

# you can also Z together two lists with an infix op
my @total-scores = @first-scores Z+ @second-scores;

# strings as keys, the appropriate number of 1s as values
my %hash = @names Z=> 1 xx *;              # xx is list repeat

# line people up with increasing numbers
my %people2numbers = @people Z=> 1..*;

# don't have a good op? roll your own!
sub infix:<likes>($liker, $likee) { "$liker is fond of $likee" }
# note how the op infix:<Zlikes> is automatically available
my @relations = @likers Zlikes @likees;

infix:<...>

1 ... $n                                    # integers 1 to $n
$n ... 1                                    # and backwards

1, 3 ... $n                                 # odd numbers to $n
1, 3, ... *                                 # odd numbers
1, 2, 4 ... *                               # powers of two
map { $_ * $_ }, (1 ... *)                  # squares

1, 1, -> $a, $b { $a + $b } ... *           # fibonacci
1, 1, { $^a + $^b } ... *                   # ditto
1, 1, *+* ... *                             # ditto

'Camelia', *.chop ... '';                   # all prefixes of 'Camelia'

# See http://blog.plover.com/CS/parentheses.html
# for the principle behind this
sub next-balanced-paren-string($s) {
    $s ~~ /^ ( '('+ ) ( ')'+ ) '(' /;
    [~] $s.substr(0, $/.from),
        "()" x ($1.chars - 1),
        "(" x ($0.chars - $1.chars + 2),
        ")",
        $s.substr($/.to);
}

my $N = 3;

my $start = "()" x $N;
my &step = &next-balanced-paren-string;
my $end = "(" x $N ~ ")" x $N;

for $start, &step ... $end -> $string {
    say $string;
}

# Output:
# ()()()
# (())()
# ()(())
# (()())
# ((()))

Rakudo Star releases in a week, July 29th.

Sunday July 18, 2010
02:34 PM

Happy 10th anniversary, Perl 6

On this date exactly 10 years ago, Jon Orwant threw coffee mugs against a wall during a meeting. Wikipedia chronicles the announcement of Perl 6 as being on July 19 ten years ago... but the throwing of mugs on the 18th can be said to spark the birth of Perl 6.

Why did he throw mugs? Larry Wall's own explanation covers it in sufficient detail:

We spent the first hour gabbing about all sorts of political and organizational issues of a fairly boring and mundane nature. Partway through, Jon Orwant comes in, and stands there for a few minutes listening, and then he very calmly walks over to the coffee service table in the corner, and there were about 20 of us in the room, and he picks up a coffee mug and throws it against the other wall and he keeps throwing coffee mugs against the other wall, and he says "we are fucked unless we can come up with something that will excite the community, because everyone's getting bored and going off and doing other things".

And he was right. His motivation was, perhaps, to make bigger Perl conferences, or he likes Perl doing well, or something like that. But in actual fact he was right, so that sort of galvanized the meeting. He said "I don't care what you do, but you gotta do something big." And then he went away.

Don't misunderstand me. This was the most perfectly planned tantrum you have ever seen. If any of you know Jon, he likes control. This was a perfectly controlled tantrum. It was amazing to see. I was thinking, "should I get up and throw mugs too?"

When I thought up this blog post, I knew about the incident but wasn't sure when it had happened. I made some Internet research on my own, and couldn't really find a source mentioning the day of the mug throwing.

I did find this email, which outlines the participants and the number of mugs thrown.

In the end, I asked Larry Wall on IRC about the date. The ensuing pun-ridden discussion is quite typical of #perl6.

<TimToady> masak: btw, the mugs were the day before
<jnthn> mugs? I thought it was just one mug!
<masak> jnthn: five.
<masak> jnthn: only one broke, though.
<masak> TimToady: thanks. still time to prepare for an anniversary blog post,
        then.
<jnthn> masak: Smashing.
<TimToady> I wish I'd collected the broken mug
<masak> "Perl 6: breaking mugs and backwards compat since 2000"
* pmichaud fires up photoshop, looks to cafepress
<masak> pmichaud: "Perl 6: the greatest language ever to emerge out of the
        shards of a mug."
<pmichaud> "Break mug in case of language stagnation."
<jnthn> "Perl 6. It's Perl 5 with a cupple of improvements."
<pmichaud> "Perl 6 mugs -- another lucky break!"
<masak> "if $mug === all @shards { say 'We need a break from all the mug puns!' }
<jnthn> Oh, you can handle it. :P
* masak shatters from laughter
<TimToady> "Why's Jon throwing donuts?"  --topologist
<masak> :P
<TimToady> "This is a broken mug.  <mug> This is your brane on broken mugs.
           <camelia> Any questions?"
<masak> "Perl 6: seeking the holy grail after accidentally smashing it ten
        years ago."
<jnthn> "How is mug re-formed?"
<masak> They need to do way instain Jon Orwant.
<jnthn> Who harms 5 mugs that cannot frigth back!
<masak> My pary are with the cleaner.
<masak> "Perl 6: poculum iacta est."

By now, Perl 6 has a 10-year history. I thought I'd spend the rest of the blog post recounting it from (mostly) my perspective. With this I hope I will manage to convey not only the actual sequence of events, but also some of my enthusiasm about the project, and why I think Jon Orwant's broken mug kicked off one of the coolest projects in modern programming language history.

The early years

Perhaps you've heard about the RFC process. This was right at the beginning of Perl 6's life, when even Larry Wall wasn't sure which direction to take Perl 6, and a system was created wherein people could send in their proposals for language features. Something on the order of 20 or 30 RFCs were excpected before the closing date.

361 RFCs were sent in.

Not only were they many more than expected; they were all over the map, mutually inconsistent, and overall each of them advocated one feature without much concern for the rest of the language. Had we somehow decided to go right ahead and just make a language of all those RFCs, we probably would have ended up with something very much like this famous parody of Perl 6.

There was also little concern for how the proposed features would be added. Mark-Jason Dominus wrote in his Critique of the Perl 6 RFC Process how a large part of the RFCs neglected to consider the implementation of the proposed features:

It leads to a who-will-bell-the-cat syndrome, in which people propose all sorts of impossible features and then have extensive discussions about the minutiae of these things that will never be implemented in any form. [...] It distracts attention from concrete implementation discussion about the real possible tradeoffs. [...] Finally, on a personal note, I found this flippancy annoying. There are a lot of people around who do have some understanding of the Perl internals.

Jarkko Hietaniemi countered with a more optimistic view of the process:

[...] now we have an idea of the kind of things (both language-wise and application/data-wise) people want to do in Perl and with Perl, or don't like about Perl. [...] Based on that feedback Larry can design Perl 6 to be more flexible, to accommodate as many as possible of those requests in some way. [...] Without the RFC process we wouldn't have had that feedback.

In the end, Larry Wall took on the work of triaging the RFCs and distilling them into a coherent whole. He did this in the form of Apocalypses, which collected the RFCs in different categories and commented on them one by one. The RFCs were either accepted with different amounts of caveats, or rejected. The Apocalypse numbers were based on different chapters in the Camel book; for example, chapter 3 of that book describes operators, so Apocalypse 3 talks about operators in Perl 6.

Here are all the Apocalypses that were published:

  • Apocalypse 1, May 2001
  • Apocalypse 2, May 2001
  • Apocalypse 3, Oct 2001
  • Apocalypse 4, Jan 2002
  • Apocalypse 5, Jun 2002
  • Apocalypse 6, Mar 2003
  • Apocalypse 12, Apr 2004

In other words, the whole period 2001-2004 can be seen as the period when Perl 6 was still being distilled from the various wishes people had about it.

Along with the Apocalypses were published same-numbered Exegeses, by Damian Conway who also had a central role in designing Perl 6. Where the Apocalypses were geared towards explaining language decisions for and against features, the Exegeses set out to showcase the new combinations of features, and to explain to Perl 5 programmers the improvements introduced in Perl 6.

Reading the Exegeses today, what's especially noticeable is the sense of Perl 6 as a variant of Perl 5. Sure there are lots of little tweaks and changes, but as Damian notes after writing a rather elaborate script in E02, "In fact, that's only 40 characters (out of 1779) from being pure Perl 5. And almost all of those differences are @'s instead of $'s at the start of array element look-ups. 98% backwards compatibility even without an automatic p52p6 translator...pretty slick!".

Not much remains of that idea today; if you'd step into the channel and ask "is Perl 6 like Perl 5?", we'd tell you that while the general goals and ideas can still be discerned, the syntax is so different that it's probably better to start learning it than try to code Perl 6 like one would code Perl 5.

In 2004, the Apocalypses were summarized down into Synopses, which contained the decisions from the Apocalypses without all the explanatory monologue. The Synopses would form a specification for Perl 6 the language, and were directed towards language implementors. They're fairly dense, but still a good read for anyone seriously interested in the language. The synopses are still normative and kept up-to-date. At the time of writing, I count 33 synoptic documents at perlcabal.org. Synopses 2 through 6 tend to be fairly stable, although changes still occur. The remainder of the synopses are still drafts for the most part, awaiting more feedback from implementations and language use.

During all this, efforts to start implementing Perl 6 were planned, started and abandoned. Already before the mug throwing and the RFCs, Chip Salzenberg started developing a project code-named Topaz in C++, which was slated to grow into Perl 6. The Topaz project, a rewrite of Perl 5 internals, was eventually abandoned. I asked Larry why, and he replied that "reimplementing insanity is insane". (Meaning "don't try to extend the Perl 5 internals into Perl 6".)

There was also a one-week exploration project called Sapphire; another rewrite of Perl 5 internals in September 2000, shortly after the announcement of Perl 6, Sapphire was mostly intended to be a sort of tracer bullet to learn things about an eventual real implementation.

Finally, Parrot was a fledgling virtual machine created with the express purpose to be good at running dynamic languages; especially Perl 6, the dynamickest language of the bunch. Ponie was an attempt to drag the Perl 5 internals, kicking and screaming, into the Parrot Virtual Machine and have them run there. The Ponie project, as can be read here suffered from a too-low bus number as well as Parrot's relative immaturity; Ponie was ultimately "put out to pasture" in 2006. An early implementation of Perl 6 on Parrot was also developed at this time, but by 2004 it had also proved to be unworkable.

As someone on the outside looking in, I knew of Parrot, but not of the other projects. I didn't know about the Perl 6 project that already existed on Parrot, only about the Apocalypses and the Exegeses, all of which I had read with interest. What happened now? Would this programming language ever become a reality? No-one seemed to know. And nothing exciting seemed to happen.

In early 2005, a certain A. Tang made an entrance, posting a short announcement on the perl6-all list of a "side-effect-free subset of Perl6". (Notice the parallels between the tone of this email and Linus Torvald's famous "nothing serious like GNU" announcement.) Before I knew it, the side-effect-free subset of Perl 6 had mutated into something called Pugs, a full-fledged implementation.

Pugs: The golden age

I remember stumbling into the #perl6 channel on freenode, still fairly dazed by the fact that someone was taking the Synopses and implementing them. Add to this that Audrey Tang turned out to be a frighteningly productive hacker with a magnetic personality which drew other people into the project like nothing I or many others had ever seen. Being on the #perl6 channel was like standing close to the eye of a hurricane; things just magically happened, either because Audrey had just landed another set of commits, or because someone had started a cool side project and was hacking on that, all the while bringing interesting ideas and thoughts into the channel.

And we were all running (an early version of) Perl 6! Operators, subs, classes, operator overloading... one by one, the cool features we had anticipated started working. We introduced bots to be able to run Perl 6 code right in the channel. Audrey threw out commit rights to the Pugs repository to anyone who made as much as a peep about possible improvements. And it worked! Hundreds of people were given commit-bits, and rather than seeing a massive amount of vandalism like you would on a wiki, we saw a great number of these people contributing constructively to the project. The slogan at that time was to "trust the anarchy", a seriously scary notion. A happy Audrey stood in the middle of it all, guiding the various efforts along, blogging almost daily, contributing insane amounts of code herself, and injecting steam into an ever-more concrete Perl 6 community.

Pugs is written in Haskell, and many of the cultural traits at the beginning came from the Haskell culture. Pugs hackers went by the moniker "lambda-camels". There was an unusually high amount of references to comp.sci. papers, and books about Haskell, and esoteric books about programming in general. A representative list can still be found in Pugs' READTHEM file. The humor was intelligent and often riffed off of some computer topic or other.

<audreyt> Alias_: my eyeglasses has style="border: none"
<Alias_> doesn't matter
<Alias_> optical edge cases at the boundaries create border: solid 1px #99999
<audreyt> true
<audreyt> though it's more like ridged in my case
* audreyt sighs at the general geekiness

<audreyt> apparently malaire++ is to blame
<audreyt> I mean, to praise
<audreyt> or to annotate

The predominant interjection was "woot!". The predominant user of the interjection "woot!" was Audrey. Karma points were the new currency, and bots roamed the channel keeping track of the karma points, or handing them out while emitting real-time commit messages.

Let me be clear about one thing: at that point on the #perl6 channel, I was a groupie. I didn't contribute significantly to Pugs, or to the discussion around the Synopses or the language itself. I did try my best to contribute to the jokes.

In March 2005, I had made enough silly noise to get a commit bit:

<autrijus> welcome aboard!
<masak> thx. i could hardly sleep last night because of pugs :)
<autrijus> all excited?
<masak> overly so
<autrijus> I know that feeling :)))

Audrey kept up a high development tempo, often leading to jokes about her productivity:

<autrijus> I'll brb -- shower &
<geoffb> So the rumors of autrijus ircing in the shower appear to be
         false . . . .
<geoffb> or maybe he just lurks, with the laptop right outside the curtain.
<autrijus> yup.
<autrijus> that's usually the case.
<autrijus> to avoid damaging the keyboard I usually type with a toothbrush
           or so.
<geoffb> LOL

<Juerd> Every *book* about Perl 6 is outdated.
<Juerd> They are outdated two hours after they are pressed.
<Juerd> By the time they are in stores, they are a month behind
<Juerd> And by the time you buy and read them, an entire perl 6
        interpreter was written by autrijus :)
<mauke> while he was sleeping!
<castaway> autrijus sleeps?
<nothingmuch> castaway: sometimes he claims that
* castaway doesnt believe it
<mauke> maybe his computer has a neural interface and he codes in his dreams
<castaway> this would not surprise me :)
<Juerd> castaway: Well, he sometimes says he's off to bed, and then after a
        few hours you see a huge commit in the logs. So I don't
        believe it :)
<castaway> hehe
<castaway> from what I figure, he sleeps only in max. 30 min chunks,
           or something
<Juerd> I think he hyperthreads

Audrey was once found saying "People think I'm this awesomely great coder, but it's really Haskell and Parsec [a parser combinator library for Haskell] that do all the magic". I didn't see people stop commenting on Audrey's prolificacy because of that, however.

Somewhere in 2006, Larry Wall joined the channel. He never really left.

<avar> ?eval <good fast cheap>.pick(2)
<evalbot_r16148> ("good", "cheap")
<TimToady> that's us all right...

We did lose Audrey, however. After her gender change, she continued work at an unabated pace; but then she was hit by a serious hepatitis infection, and disappeared in 2007 in the middle of a tough refactor of Pugs, never to return. Pugs ground to a halt. The channel became a lot quieter after she was gone.

Pugs was (and is) still around, but it had stopped evolving, and it wasn't a full Perl 6 implementation yet. The community still existed, but the central person to hold it together was manifestly missing. Not knowing what the future would hold, I longed for more Pugs.

(The reason for Audrey's disappearance didn't surface until two years later, when she made a tentative blog post about it.)

Rakudo: The silver age

Pugs sort of let the genie out of the bottle. Once Audrey had created a "rogue" project that just took off and increasingly embodied the Perl 6 idea, several other people started making "little" implementations, too. Between 2005 and now, about a dozen "little" implementations sprang into existence, several of which are still active today. Their respective goals range from exploring to actually implementing the whole language. I call them "little" mainly because they have few developers and a small user base.

While Pugs arrived with a bang and went dark just as quickly, work continued on implementing Perl 6 on top of Parrot. Progress came much more slowly here, because Parrot was an immature platform and needed a toolchain and compiler ecosystem in order to build Perl 6. Starting in 2005, Patrick Michaud began writing a grammar engine (PGE) and compiler toolkit (PCT) for Parrot. These eventually led to a fledgling Perl 6 implementation in 2007, which in early 2008 was given the name "Rakudo Perl 6". To be honest, I didn't pay much attention to it before it got the Rakudo name.

Patrick had a vision that a Perl 6 implementation needs to have a decent Perl 6 grammar engine at its foundation, followed by a good compiler-building toolchain. Once those bits were in place, Patrick turned to the actual Perl 6 compiler and runtime. An intrepid guy named Jonathan Worthington had in an unguarded moment promised Patrick to implement junctions (only to realize that junctions required multi-dispatch, which required the type system, which required much of the OO system to work...).

Together, Patrick and Jonathan put in feature after feature during the first half of 2008.

Things were happening again. It didn't look playfully effortless like with Audrey and Pugs; the features I picked up and tried out invariably broke. But things were happening again. Between Pugs, a relatively featureful project which no longer responded to pings, and Rakudo, a slow-moving but active project which could one day be made to do the things Pugs did, I gradually turned my attention to Rakudo.

The summer of 2008 is a bit of a blur. We (viklund and I) wrote a wiki engine in the not-yet-housebroken Rakudo. It was just a wacky idea we had. If we succeeded in any sense of the word, we said, we'd go to YAPC::EU and present it all in a lightning talk.

Well, we eventually made it, and we went to YAPC::EU, and we thrilled at the audience reaction upon hearing the news of someone writing a web app in Perl 6. But, um... the corners we cut on the way there. The workarounds for missing features we invented. The bugs we discovered. And it wasn't like we could just pop in on #perl6 and haul out some failing piece of code from our secret project. No; the code had to be scrubbed clean of all wiki-ness first. It was during this time I learned the value of golfing bug reports.

I submitted many bug reports that summer. All of them scrubbed. It became a bit of a thing, like when little kid starts collecting bottle caps. And it wasn't like Rakudo had a shortage of bugs. For a while, it felt like Rakudo was mostly built out of bugs. This is not meant to be a slight towards Patrick and Jonathan; they were, and are, doing an excellent job. But every project needs to be tested out in the field, and no-one had done that until viklund and I came along. I made field-testing and bug reporting into a sport, going round in a never-ending cycle of doing something new with Rakudo, seeing it break, and submitting a bug ticket about it.

It felt pretty good to be not so much of a groupie any more, and more of a contributor. Since then I've written a lot of Perl 6 code, and even gotten a Rakudo commit-bit... but I suspect I will remain "the guy who submits all the bugs" for a long time hence.

The current cultural references seem to lean heavily on lolcat references, exotic smilies, and other contemporary internet memes. Makes for a light-hearted atmosphere, and the contrast between lolcats and compiler guts is often quite refreshing.

<pmichaud> good morning, #perl6
<jnthn> morning, pmichaud
<PerlJam> greetings pm
<colomon> o/
<mathw> o/ pmichaud
<moritz_> /o/
<mathw> \o\
<jnthn> \o/ |\o/| o< /o\
<jnthn> ;-)
<mathw> aaaaargh
* mathw hides
<okeCay> o/\o !

As Rakudo keeps maturing, the Synopses change with it. This is scary to some. How can one start learning a language that keeps changing? Why won't the specification keep still? I can only speak for myself on this issue: I wouldn't want the specification to be "locked down" or "frozen", not as long as the changes going into it are ever-smaller adjustments, most of them responses to insights gained from implementations like Rakudo. On the one hand, the Perl 6 specification changes more than for any other language I know; on the other hand, it's becoming more stable by the day. We call it a kind of "whirlpool development", where later steps in the process are allowed to affect earlier ones, but things are successively centering on one single point.

IRC can be quite a brusque and unforgiving place, but the #perl6 channel has a reputation as one of the kindest places on the Net. A huge amount of time is spent answering newcomers' questions, helping sort out people's syntax errors, clarifying language terms and design decisions to outsiders and to ourselves, reviewing code, reviewing each other's blog posts, and generally making people feel welcome and cared for on the channel. #perl6 almost never sleeps entirely nowadays, since it has active participants from all over the globe. While we do feel that we have a really cool language to showcase to the world, we're also quite proud over the quality of the Perl 6 culture.

The story with Rakudo since 2008 is that it's slowly established itself as the front-runner among implementations, even surpassing Pugs in most areas. Rakudo now has most of the operators and control structures in place, excellent regexes and grammars (thanks, Patrick!), excellent OO and multi dispatch (thanks, Jonathan!), and many other very solid features. There are many other smaller implementations which help drive the spec and scout the solution domain in various ways; but Rakudo is the one with the most person-tuits put into it by far nowadays. The list of contributors in the monthly release announcement usually lands at a couple dozen people. Perl 6 is again arriving a little more every day. Life is good. I'm still submitting about one rakudobug a day, but the things submitted are increasingly more high-level and less and less about glaring omissions.

The action in the past year has been a pretty huge refactor, first of the grammar subsystem, but then of various other subparts that needed ripping out and rewriting. Inwardly, this has been known as a number of smaller projects all being part of a big Rakudo refactor. Outwardly, it has been known as the imminent release of Rakudo Star.

Rakudo Star: Perl 6 takes off

Ok, so this part of history hasn't happened yet. But it's about to. On July 29, the Rakudo team is releasing Rakudo Star, the first distribution of Rakudo Perl, a Perl 6 implementation. (Info links here, here, and here.)

I find it quite fitting that 10 years and a couple of days after the Jon Orwant mug that started it all, the Perl 6 people come forth and say "Here. We made this, and it's at a first stage of ready. We've been tinkering with it for quite some time, fixed a lot of bugs and polished the pearl to a relative shine. We'd like you to try it out and make something cool with it."

I, and many people with me, have been excited about this porcelain descendant for many years now. It's time to let a bigger circle of people in, and let them get excited as well.