qk: Quote Membership Hash Keys

I recently ran across an article (http://neilb.org/2016/08/08/quoted-words-arrayref.html) by neilb, advocating for a qa() operator that returns an arrayref instead of a plain array:
  our $cars_ref = qa(sedan hatchback coupe);
I love this idea, and I would use it a lot.

I’d like to add onto this proposal another qw()-style operator to quote the keys of a membership hash. I suggest qk() for “quote keys.” So
  our %is_color = qk(red blue green);
is the same as
  our %is_color = map { $_ => 1 } qw(red blue green);
  our @colors = qw(red blue green);
  our %is_color = map { $_ => 1 } @colors;

Unlike my previous entry (symbolic “xor”), I wrote this line of code ALL THE TIME. Taking a cue from neilb, I looked on CPAN to see how often other people do this. It turns out the answer is “a really, really lot”: http://grep.cpan.me/?q=map%5Cs*%7B%5Cs*%5C%28%3F%5Cs*%5C%24_%5Cs*%3D%3E%5Cs*1%5Cs*%5C%29%3F%5Cs*%5C%7D%5Cs*qw


I like your idea, although I found the result of qk() quite surprising. It's useful after all.

However, I suggest writing my $arrayref = qa[foo bar] to make it look like an arrayref constructor.

Well, if you're going to document qa() as qa[], you should then use qk{}, no?

I’m not a fan of either proposal, though especially not of qa(), because of how little they offer, and how easily they are replicated by just chucking a few functions into List::Util:

our $cars_ref = array qw(sedan hatchback coupe);
our %is_color = members qw(red blue green);

… and though array may not seem worth it, it does have the advantage over [] that you can often leave off the parentheses in the function call, in which case it offers prefix notation rather than the built-in circumfix.

Then old perls can easily run this code by just upgrading their List::Util.

A thought I’ve had a number of times, though, is that I’d like for simple slices to be allowed within declarations, so you could say things like this:

our @is_color{qw(red blue green)} = (1) x 3

… and this would declare %is_color while assigning to it. And same thing for array slices.

This feature generalises to many more situations than qa() and qk, e.g.

sub new {
    my ( $class, @self{qw( id name label )} ) = @_;
    bless \%self, $class;

The problem is that we don’t have someone like Larry any more who a) tries to keep the design of the language as a whole in their head and b) has the legitimacy to say “no” to nice-looking but ultimately ill-fitting proposals for consistency reasons. (And I’m not saying it’s my proposal that Larry would keep; maybe mine is the crazy one, and he would go with something completely different.) This was of course precisely the problem with the RFC process that factored into why Perl 6 became such a huge undertaking – namely, almost every proposal was one-off solution focused on one corner of the language, and however reasonable they were individually, putting all of them together would have made a huge mess of the language.

I could live without either. I think qk() is more useful than qa(), given that qa saves you two non whitespace keystrokes:

my $aref = qa( a b c );
## vs
my $aref = [qw( a b c)];

And yes, Aristotle is correct; qk() is the better syntax given usage would be

my %h = qk( a b c )

And if you want a hash ref, then this should be sufficient:

my $h = { qk(a b c ) };

Leave a comment

About morandimus

user-pic My real name is Jeremy Holland. I've been a programmer for 25 years, using primarily Perl since 2000.