Enough
advocacy, let's get to the nitty gritty of 5 things I hate about Perl.
(After brian d foy.)
-
The difference between list and scalar context is subtle. One bug that bites people too
often is this (for some value of "people", including me, far too often):sub myfunc { return }
my $scalar = myfunc(); # contains undef
my %hash = (
key => 'value',
key => myfunc(),
);In scalar context, we get undef. But in list context, myfunc returns
a list of zero elements. Guess which context hash declarations are in…Luckily in this case we'll get a "Odd number of elements in hash declaration" warning.
Perl's warnings are mostly very useful and surprisingly helpful. However: -
Some warnings suck. Yes, some of them almost always point out an error (the void context
error is useful: I usually find it means I've written: my $x => 1 instead of
my $x = 1) but some are more irritating.When was the last time an 'uninitialized' warning had any effect on your code apart from making
you have to sprinkle $x ||= '' throughout your code? Yet I usually restrain
myself from adding no warnings 'uninitialized' because maybe one time in a hundred
there's a genuine bug I need to know about.Similarly 'once' warnings sound useful, but in practise are usually because you've
referred to a magic global that's used plenty of times in the library you want to use.
For example, from List::Util's documentation,my $sum = reduce { $a + $b } @list;
will warn about $main::a and $main::b being used only once. $a and $b are the canonical
magical variables, wtf is that about? (mst suggests that these warnings are inhibited
for sort only, which was their first use case). -
Argument passing. Yes, it's really flexible to be able to unpack
@_ in any way you want but I'd like a proper way of doing it. (And yes,
there are all kinds of solutions including Devel::Declare, but none are
standard yet). Oh, and we don't have full destructuring bind, so yes, you can
do ($x,$y) = ($y,$x) and my ($self, %args)=@_, but not my
({foo=>$foo}, [undef,undef,$bar]) = @_. -
It's a big language, with lots of syntax, several powerful minilanguages, a vast array of
standard idioms, a large set of standard libs (including various incompatible ways of doing
similar tasks) and a truly staggering number of 3rd party libs, CPAN, with even more ways of
doing it. Actually, learning a big language is fine, but the bigness is one of the things
making Perl difficult to parse. The other is the sheer amount of flexibility that Perl
gives you to shoot yourself in the foot, change the way the language is parsed etc. Only
Perl can parse Perl, and usually only after executing part of your code first. Yay for exploits
on your language-aware text editor! -
Functional programming isn't easy or elegant. Yes, we have first class
functions, but things like argument unpacking being ugly make it less
convenient. Little kludges like the functions passed to map and grep taking
$_ rather than the usual argument list @_ just add to the fun
($_ seems like a special-cased points-free hack, and it's far less
consistent or common than Haskell's currying)I also dislike that regex substitution etc. can't be done as a non-destructive function.
Hmmm, there are probably more things, but those are the main ones. In particular
I don't hate references (yes, they take a little learning, and I'm aware that's a
stumbling block for most learners, but they are quite sensible once you do)
or OO (baroque, but quite capable, and see Moose for a cute modern take on
it).