Inadvertent Inconsistencies: Aggregate Autoderef in 5.14

Perl 5's dereferencing syntax has always been ugly. It's perhaps the ugliest part of the language's syntax. (Some people think regular expressions are ugly. They are, but they have a long history of being ugly. You don't blame the human knee for being unattractive when it does what it does as effectively as it does, but you also don't reproduce its ugliness when you design an entirely new lifeform.)

Perl 5's aggregate operators (such as push and shift) have traditionally required dereferencing when used on aggregate operands. In other words, through most of Perl 5's lifespan you had to write:

my $diversions = [ 'Halo', 'LoTR Pinball', 'Cat Herding', 'Mario Galaxy' ];

my $evening_event = shift @$diversions;
# or shift @{ $diversions }

The same goes for hash operators:

my $pet_nicknames =
    Lucky  => 'Stinkerbell',
    Rodney => 'Robot Parade',
    Choco  => 'Destructo Junior',

my @nicknames = values %$pet_nicknames;
# or values %{ $pet_nicknames }

Although Perl can warn you when you mention the wrong variable if you use first-class aggregates (writing keys %not_a_hash when there's no hash called %not_a_hash in scope, for example), you have no such protection at the point of compilation when you dereference aggregate references. If $pet_nicknames turns out not to be a hash, you get a runtime error.

That's all well and good; we've lived with that through Perl 5's lifespan and we know how to deal with that. Keep that in mind, though.

Perl 5.14 added a feature by which Perl will do what you mean when you provide a scalar as the operand to one of these aggregate operators. In other words:

my @nicknames = values $pet_nicknames;
my $evening_event = shift $diversions;

Because it's unambiguous that shift must operate on an array, Perl will happily now dereference $diversions as if it were an array. If it isn't an array, you get the same error that you'd have received if you'd written @{ $diversions } or @$diversions on something that isn't an array.

Removing extraneous superfluous bletcherous syntax is generally a good thing, if it's truly unnecessary and unambiguous. In the case of array operators, it is.

Then we come to hashes.

As of Perl 5.12, the hash operators work also on arrays. Again, that's usually okay. If you write each $diversions or values $diversions or even keys $diversions (though why would you do either of the latter? rhetoric parallelism in Perl poetry?), you'll get something sensible back...

... except that you don't get the protection you'd get if you'd written %{ $diversions } or %$diversions when $diversions is an array reference.

Obviously making shift and push autodereference aggregates implies making the other array operators autodereference aggregates, and making the array operators autodereference aggregate implies making the hash operators autodereference aggregates. Consistency is a good thing.

Yet the combination of these two features in two Perl releases has produced an inadvertent inconsistency such that using these features together is a little bit less safe than not using them.

This isn't the worst of it; the next post will explain how things can go worse, how to avoid these problems in your code, and how they could have been avoided at the design and implementation levels—and why they weren't.

Modern Perl: The Book

cover image for Modern Perl: the book

The best Perl Programmers read Modern Perl: The Book.

sponsored by the How to Make a Smoothie guide



About this Entry

This page contains a single entry by chromatic published on March 21, 2012 12:18 PM.

Inadvertent Inconsistencies: each in Perl 5.12 was the previous entry in this blog.

Inadvertent Inconsistencies: each versus Autoderef is the next entry in this blog.

Find recent content on the main index or look in the archives to find all content.

Powered by the Perl programming language

what is programming?