Monday, August 31, 2009

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

Okay, this is really part 1b of ?, but…

In my earlier post, I used the zip operator to join two lists into a hash.

There was one obvious use of the operator that escaped me at the time, and that was how I sometimes need to create a new hash from the keys of two hashes, or keys and values. And now I think it's starting to look neat:
my %A = { a => 1, b => 2 };
my %B = { z => 9, y => 8 };

my %AB = %A.keys Z %B.keys;
# { "a" => "z", "b" => "y" }

%AB = %A.keys Z %B.values;
# { "a" => 9, "b" => 8 }
However, this is a bit unpredictable, since the hash key order is undefined. So if you expect sorted keys, do that at the same time:
%AB = %A.keys.sort Z %B.keys.sort;
# { "a" => y, "b" => z }

# Sort by B's values - two variants
%AB = %A.keys.sort Z map { %B{$_} }, %B.keys.sort;
%AB = %A.keys.sort Z %B.sort.map( { .value } );
# { "a" => 8, "b" => 9 }
The equivalent Perl 5.10 version would be:
use List::MoreUtils qw/zip/;
my @k = sort(keys(%A));
my @v = map { $B{$_} }, sort(keys(%B));
%AB = zip @k, @v;

I now have a nice-ish argument for upgrading to Perl 5.10.1 on $workplace's servers. :D

masak++ for helping a tired me with the map expression.
Chas. Owens++ for spotting the missing use statement for Perl 5.
Pm++ for another way of sorting by value, just what I was hoping for!
isec++ for spotting a missing sort() for Perl 5.

Sunday, August 23, 2009

Autovivification - a reminder

Most of you already know this by heart, but the odd reader may have forgotten.

Autovivification is what we call the process of automatically creating entries in built-in data structures (Perl 5: array/list and hash), usually at the time we check whether an inner element exists or not.

This can be a royal PITA, if you don't pay attention to the problem. That's why it keeps being mentioned.

Here's a simple example:

my %hash;
my $n;
while (!exists ($hash{x}) && $n < 5) {
$n++;
if (!exists ($hash{x}{y}) {
print "hash{x}{y} does not exist: $n\n";
}
}

Q: How many times does the above while loop run in Perl 5?
A: Once.

The simple matter of checking the existence of the inner hash resulted in an entry being created for $hash{x}.

That means that tests like these should be written more carefully:


if (defined ($hash{x})) {
if (!exists ($hash{x}{y}) {
print "$n: hash{x}{y} does not exist.\n";
}
} else {
print "$n: hash{x} is undefined.\n";
}

This prints $n: hash{x} is undefined. (with an incrementing $n) five times.


Edit 2009-08-24 18:49 UTC: MST commented that there is an autovivification module on CPAN that lets us say no autovivification; - and it's even lexically scoped! That's just $notreallyanexpletive brilliant! Thanks, Matt, and thanks, Vincent!


Oh, BTW, Perl 6 has a useful specification for autovivification, which illuminates the problem further.

Sunday, August 16, 2009

Hash key sort order - a Perl 6 community sunshine story

The order of hash keys is implementation dependent and arbitrary. Unless %hash is altered in any way, successive calls to .keys, .kv, .pairs, .values, or .iterator will iterate over the elements in the same order.

S09 - Hashes

This is new. It may not actually say much, but it does say what was implicit before, so that there is little room for doubt.

So here's my little sunshine story about how easy it is to clarify a part of the spec.

In my previous post, I used an imaginary case for showing off some features of Perl 6 - some of which also are available in Perl 5.10, as mentioned by Robert 'phaylon' Sedlacek in a comment.

This wasn't the only useful comment, I think there's a bit to be learned by reading those, so please do.

But I digress from the point of this post, which is a question that was raised in another comment to last Sunday's post:

By the way, do you know where the behavior of ~%h is spec'ed? I keep getting the keys back in the same order I put them in and don't know if that is an implementation quirk or a feature.

- Chas. Owens

The spec wasn't very clear about this; S32/Containers - Hash said that certain iterator methods iterate "… the elements of %hash in no apparent order, but the order will be the same between successive calls to these functions, as long as %hash doesn't change."

S09 - Hashes didn't say anything about it at all.

I said I would ask around. Thanks to the excellent community channel #perl6 on Freenode, I got an answer similar to this: no, this is unspecified/undefined behaviour, but feel free to come up with a better way of saying it, and update the synopses.

And how hard is it to update the synopses? Not at all! If we want to contribute, we get access. It's as easy and simple as that.

First, you need to check out the (part of) the svn repository that you want to contribute to:

svn co http://svn.pugscode.org/pugs/docs/Perl6

Then you change whatever you want to change, preferably discuss it with some of the experienced souls on #perl6 or e.g. the Perl 6 language mailing list, show diffs on e.g. gist.github.org or paste.lisp.org, and if you think you're doing the right thing - commit the change.

"But I can't commit, I only have read access" you might say. Just ask in any of the mentioned fora for a "commit bit" and state your e-mail address and preferred username, and someone will help you out with that part.

As we say on #perl6: community++

I got started, will you join me?

Sunday, August 9, 2009

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

(After YAPC::Europe in Lisbon, we no longer say "awesome", we say "grand". ;))

In Lisbon, there were several talks that aided us to a better understanding of how Perl 6 may be more pleasant and useful than Perl 5.8, or even Perl 5.10.

I thought I'd try to illuminate some of these as I progress in my own knowledge of Perl 6.

First choice: the zip operator and the new quoting syntax for generating lists and selecting items from hashes:

my @months = <Jan Feb Mar Apr May Jun Jul Aug Sep Oct Nov Dec>;
my %days = @months Z 31,28,31,30,31,30,31,31,30,31,30,31;
say "Days in March: " ~ %days<Mar>;
say "Days in June: {%days<Jun>}";
say ~%days;
That was quite a bit in one go. :) First, I create a new list of abbreviated month names. Then I combine the list of months with a list of days in that month (for 2009, obviously) using the zip (Z) operator, and print the number of days in March and June. Finally, I pretty-print each month with the corresponding number of days.

The result looks like this:

Days in March: 31
Days in June: 30
Jan 31
Feb 28
Mar 31
Apr 30
May 31
Jun 30
Jul 31
Aug 31
Sep 30
Oct 31
Nov 30
Dec 31
Now imagine what that would have to look like in plain Perl 5.

There are several new things here that makes your programming days easier:
  1. The well-known sigils $, @ and % are now used in a consistent manner. @ signifies a list, % signifies a hash, also when you access items by index.
  2. Interpolation of non-scalars is now handled with curly brackets {}.
  3. Building a list can be done using commas, no parentheses are necessary.
  4. Building a quoted list can be done using angle brackets, which are auto-quoting.
  5. Accessing a hash item is done using angle brackets, which should be welcome to those of use who don't use US/UK keyboards (bye-bye to {'argh'}, but it still works).
  6. say is a new pretty-printing friend, which automatically adds newlines.
  7. The concatenation operator is now tilde (~) instead of a period.
  8. As a unary prefix operator, tilde by default stringifies a hash pair-wise with newline separators (while a list is stringified with space separators). It is possible to change this behaviour in derived subclasses.

Edit 2009-08-10 08:34-09:18 UTC: Clarified and added interpolation.

Tuesday, August 4, 2009

Mini report from YAPC::Europe 2009

The second day of the conference is now finished.

Yet again, the lightning talks have been a great source of entertainment, but the best regular entertainment were probably Paul Fenwick's and Damian Conway's sparring ... in Klingon.

If you can lay your hands on the video of their respective talks, see them in order, and enjoy the show.

You might also learn some really interesting Perl as well, or fall deep into the pits of insanity.