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.
Ah, first, remember this statement. It's a nice hint for other software if you want to continue using theuse v6;
.pl
file suffix instead of .p6l
etc.Variables starting with the twigilmy $verbose = 1;
my $logfile = "/tmp/test.log";
my $*PREFIX = "plog";
$*
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.$*PREFIX now has a different value only for the cases where we've called thesub plogwarn ($msg)
{
my $*PREFIX = "plogwarn";
plogwarn
subroutine, and the subsequent call to plog
inherits this value.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 thatplog $msg,1;
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.The trait}
sub plogdie ($msg)
{
my $*PREFIX = "plogdie";
plog $msg,2;
exit 1;
}
sub plog ($msg is copy, $level?)
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.Normally, I'd use{
my $dt = Time.gmtime.date.iso8601
~ " "
~ Time.gmtime.time.iso8601;
localtime
, but this is NYI (not yet implemented) in Temporal.pm
.Here, I abuse that
$msg = ($dt,"[$*PREFIX]",$msg).join(" ");
is copy
to save myself one precious variable, just as an example.The
if $verbose {
given $level {
when 1 { warn $msg; }
when 2 { die $msg; }
default { say $msg; }
}
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.Here's another use of a contextual variable, but this time it's the one normally associated with STDOUT.}
# Append message to $logfile
my $*OUT = open $logfile, :a;
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 >>
).This is how we can use the three subroutines, and the output should illustrate the different contextuals nicely:say $msg;
$*OUT.close;
}
…outputs…
plog("Oh, hello, there, sweetie.");
plogwarn("Consider yourself warned");
plogdie("Die, frackin' monster, die!");
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;
}
No comments:
Post a Comment