Wednesday, September 30, 2009

Contributing to Perl

Inspiration is a big bother, at least when you don't have it.

I never felt that I had anything to contribute to the Perl community until the Nordic Perl Workshop this year, when I suddenly was involved in a small way.

I'm still involved in a small way, and only occasionally, but that works rather well.

In retrospect, my expectation that contributing would be a Big Deal turned out be wrong.

I don't have to solve all the problems in the world, and I don't have to solve the Big Ones, either.

It doesn't even take much of my time, and this level of contribution is one that suits many people.

Inspiration comes from the impression I have that there are many more people like me, and that all those little trickles of water we add to the pool are enough to keep the more active contributors going.

What is difficult, however, is to keep up with the Iron Man blogging challenge. I knew it would be when I got started, but I figured that there would always be something to write about without seeming too inane.

Today's post shows that I was wrong on that count. :D

Wednesday, September 23, 2009

I blame society

This is only vaguely Perl-related.

This weekend, I visited Abigail and her spouse in their home in the Netherlands.

I know Abigail from several settings, and Perl is one of them; Abigail has taught me many cool finesses in Perl 5, which has saved me considerable time both personally and professionally.

The friendships and connections we make "virtually" can also be very strong IRL, and I feel that has been the case with us.

If there is a point to this post, then that is: visit your Perl friends!

Sunday, September 13, 2009

Some ways that Perl 6 is grand, part 3 of ?

I'll be really brief this time, I promise!

Several things about Perl 6 are there to save programmer time. Some of them even will do so. ;) This week's favourite is pure laziness. Let's imagine we have one of those lists with month names in them again, and for some odd reason only want to do something to each third month.
for ^12 :by(3) {
say @months[$_];
}
I think that's just neat.

The caret notation is the "upto" operator, and shorthand for a range from 0 and up to its argument. So in the example above, we're asking for a range from 0 and up to 12.

The by adverbial is new in the specification. It denotes the increments for the upto operator, and allows e.g. real numbers, so that you can increment by 0.25 if it makes sense for your code to do so.

The above example then essentially iterates over 0, 3, 6, 9.

The by adverbial isn't yet implemented in Rakudo (well, duh, the spec just saw it added), where you have to settle for this for now:
for ^4 {
say @months[$_*3];
}
… and something different if you want to increment by 0.25. I hope you don't want to increment through the list of months by 0.25.

Sunday, September 6, 2009

Print-and-log in Perl 6

In one of my early blog entries, "Simple print-and-log subroutine", I shared a small piece of code that has been a nice, every-day tool - in Perl 5.

Today, I set about converting that to a naïve Perl 6 version, and being quite the Perl 6 n00b still, I ran into a few hurdles along the way.

The hurdles were easy enough to avoid, once masak++ and moritz++ had bonked my head sufficiently.

I'll walk through the code, step by step, to illustrate what I learned today, and what others might need to know.
use v6;
Ah, first, remember this statement. It's a nice hint for other software if you want to continue using the .pl file suffix instead of .p6l etc.
my $verbose = 1;
my $logfile = "/tmp/test.log";

my $*PREFIX = "plog";
Variables starting with the twigil $* is what we call contextual variables, and they just started working yesterday in Rakudo. Contextual variables follow a dynamic call path. When we reuse this variable later, it will depend on which call path we followed.
sub plogwarn ($msg)
{
my $*PREFIX = "plogwarn";
$*PREFIX now has a different value only for the cases where we've called the plogwarn subroutine, and the subsequent call to plog inherits this value.
  plog $msg,1;
Oh, BTW, it's really, REALLY important to keep track of where you add whitespace or not. I'd been sleeping and class, and forgotten completely that plog($msg,1) would call plog with the parameters $msg and $1, while plog ($msg,1) would call plog with the single parameter ($msg,$1) (yep, a list). It may be safer to avoid parentheses altogether when you're not dealing with lists - except when you have to.
}

sub plogdie ($msg)
{
my $*PREFIX = "plogdie";
plog $msg,2;
exit 1;
}

sub plog ($msg is copy, $level?)
The trait is copy means that I want to make a copy of the incoming parameter $msg, so that I can modify it inside of plog. Normally, parameters in Perl 6 are read-only and pass-by-reference (though not "reference" as you know it from Perl); the parameter as named is merely an alias for the actual variable. I can change the parameter in the caller if I use is rw, but that's not what I want to do here. The question mark in the second parameter - $level? - means that the parameter is optional, and I've used that in both plogwarn and plogdie above.
{ 
my $dt = Time.gmtime.date.iso8601
~ " "
~ Time.gmtime.time.iso8601;
Normally, I'd use localtime, but this is NYI (not yet implemented) in Temporal.pm.

$msg = ($dt,"[$*PREFIX]",$msg).join(" ");
Here, I abuse that is copy to save myself one precious variable, just as an example.

if $verbose {
given $level {
when 1 { warn $msg; }
when 2 { die $msg; }
default { say $msg; }
}
The given…when construct is similar to the switch…case construct in other languages, but subtly different, as it allows more possible values and value types than most. Coming from a world of Perl 5.8 and older, this is simply lovely.
  }
# Append message to $logfile
my $*OUT = open $logfile, :a;
Here's another use of a contextual variable, but this time it's the one normally associated with STDOUT. print FILEHANDLE $msg is no longer necessary, because you can always assign $*OUT in its own scope. The open statement has :a to indicate that I'm opening for append (so the syntax is less unixy than Perl 5's >>).
  say $msg;
$*OUT.close;
}
This is how we can use the three subroutines, and the output should illustrate the different contextuals nicely:

plog("Oh, hello, there, sweetie.");
plogwarn("Consider yourself warned");
plogdie("Die, frackin' monster, die!");
…outputs…
2009-09-06 19:59:32 [plog] Oh, hello, there, sweetie.
2009-09-06 19:59:32 [plogwarn] Consider yourself warned
2009-09-06 19:59:32 [plogdie] Die, frackin' monster, die!

And here's the complete example code, which works with the current Rakudo:
use v6;

my $verbose = 1;
my $logfile = "/tmp/test.log";
my $*PREFIX = "plog";

sub plogwarn ($msg)
{
my $*PREFIX = "plogwarn";
plog $msg,1;
}

sub plogdie ($msg)
{
my $*PREFIX = "plogdie";
plog $msg,2;
exit 1;
}

sub plog ($msg is copy, $level?)
{
my $dt = Time.gmtime.date.iso8601
~ " "
~ Time.gmtime.time.iso8601;

$msg = ($dt,"[$*PREFIX]",$msg).join(" ");

if $verbose {
given $level {
when 1 { warn $msg; }
when 2 { die $msg; }
default { say $msg; }
}
}
# Append message to $logfile
my $*OUT = open $logfile, :a;
say $msg;
$*OUT.close;
}