-
When Magics Collide
2007-01-12 21:00 in /tech/perl/HallOfShame
I haven’t posted a Hall of Shame entry in a while, and this one adds a new twist. Today, it’s perl itself that gets the blame. (I know, some will say that’s always the case.) This is about when two magics collide.
There are a couple magic tokens that you can use in perl scripts to represent the current context, like
__PACKAGE__
and__LINE__
. These tokens behave differently from variables, and one example of this is that they don’t interpolate inside strings.For reasons of backwards compatibility, when perl encounters a bareword that it doesn’t recognize, it ‘auto-quotes’ it (treats it as a string). This is generally considered A Bad Thing and the
strict
pragma forbids it. Except for when it doesn’t, and that exception is hash keys. So, even withstrict
, a bareword hash key is magically auto-quoted.Now, consider this code:
package foo; use strict; my %h; $h{__PACKAGE__} = "bar"; while (my ($k, $v) = each %h) { print "$k => $v" };
I think it’s clear that anyone writing this code expects the output to be
foo => bar
Unfortunately, it’s actually
__PACKAGE__ => bar
What’s happened is that perl has auto-quoted the string before doing the token substitution. In order to get the desired behavior, it’s necessary to resort to atrocities like
$h{__PACKAGE__ . ""} = "bar";
or
$h{+__PACKAGE__} = "bar";
to get the job done
-
Exponential Growth is Fast
2005-04-27 22:05 in /tech/perl/HallOfShame
The following is a good way to use up all your memory amazingly quickly:
my $special_chars = "!@#$%^&"; ... sub munge { ... $special_chars = quotemeta($special_chars) ... }
[Aside: I’ve come to realize that a risk in this “Hall of Shame” business is that coworkers might take offense. So, let me make a comment or two. First off, a healthy fraction of these examples are actually things that I wrote at one point, so I do try to be fair. Second, my intent really is to teach, and maybe amuse occasionally, not to ridicule; I hope that someone, somewhere will avoid stepping into the same trap.]
-
use vars
, dammit!2005-03-18 11:00 in /tech/perl/HallOfShame
Or
our
if you prefer. Whatever you do, don’t refer to variables in the current package using the full, explicit package name. Concretely, don’t say,@My::Package::ISA = qw( My::SuperClass );
Instead, write
our @ISA = qw( My::SuperClass );
or
use vars qw( @ISA ); @ISA = qw( My::SuperClass );
The problem with the first is that it is typo-prone. If you typo the package name,
perl -cw
won’t complain (in fact, perl will happily do exactly what you said), but you’ll get errors like ‘Can’t locate object method “foo” via package “My::Package”’. This is particularly likely to happen when you create a new subclass and copy the old subclass to use as a template. The alternatives are typo-proof, and easier to read to boot.(BTW, this is a specific case of the general principle Don’t Repeat Yourself. In this case, you already typed the package name once in the
package
directive. Doing it again anywhere else in the file is just asking for trouble sometime later.) -
Can you spot the bug?
2005-02-03 13:49 in /tech/perl/HallOfShame
Can you spot the bug in this code?
use strict; use constants { STATE_A => 0, STATE_B => 1, STATE_C => 2, }; ... if ($state == STATE_A) { do_a(); } elsif ($state == STATE_B) { do_b(); } elsif ($state == STATE_C) { do_c(); } else { die("bad state: $state"); }
(more)
-
Useless Use of $_
2004-09-23 20:58 in /tech/perl/HallOfShame
A new feature — my Perl Hall of Shame, featuring occasional snippets of perl code that someone actually wrote. Today, a little pattern I’ll call “useless use of $_”:
for ( 0..9 ) { my $i = $_; for ( 0..9 ) { my $j = $_; ... } }
I think that perhaps the author of this was trying to avoid polluting the enclosing lexical scope with his loop variables, but wasn’t aware that exactly the same thing can be achieved without resorting to punctuation variables:
for my $i ( 0..9 ) { for my $j ( 0..9 ) { ... } }