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.
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.