Google Groups no longer supports new Usenet posts or subscriptions. Historical content remains viewable.
Dismiss

Why it's stupid to `use a variable as a variable name'

44 views
Skip to first unread message

Mark-Jason Dominus

unread,
Jun 10, 1998, 3:00:00 AM6/10/98
to

People show up in comp.lang.perl.misc all the time asking how to use
the contents of a variable as the name of another variable. For
example, they have $foo = 'snonk', and then they want to operate on
the value of $snonk.

That's very easy to do in Perl, so they usually get some people to
tell them to do it. And they usually get some people asking them why
they didn't use a hash instead. Sometimes I'm one of the people who
says to use a hash instead, and sometimes I'm one of the people who
answers the question that was asked, even though I think they should
be using a hash instead.

Anyway, a couple of weeks ago one of my clients called up with some
program that was producing wrong reports. They needed it to be fixed
by the following day. The program was going to read a database with
records like these:


this red something
that green something else
other red more
this blue still more

and build a report of how many records had each value in each
position.

It turned out that the clods who had written this program had done
something like this:

while (<RECORDS>) {
chomp;
@values = split /\t/, $_;
foreach $v (@values) {
$$v++;
}
}

print <<EOM;
Question 1:
$this users said `this'. $that users said `that'.

Question 2:
$red users said their favorite color was red.

... (and so on ) ...
EOM

Of course, the actual code was much longer and much more obfuscated.

Anyway, to make a long story short, the problem turned out to be that
there was a certain response, let's say `foo', (actually, it was
`digoxin'---go figure) which was a valid response for two totally
unrelated questions, say #7a and #11. So anyone answering `foo' to
question 7a would be counted as having answered `foo' to question 11
as well, and vice versa. At the end of the analysis, the $foo
variable contained the *sum* of all the users who answered `foo' to
either question 7a or to question 11. Then the reports used this sum
in two places, and that's why the reports were inaccurate.

This shoddy logic was so pervasive in the program that I couldn't find
an easy way to fix it. If the original programmers had used a series
of hashes instead of stuffing everything into a bunch of global
variables, it would never have happened, or at worst it would have
been easy to fix. I ended up doing a major overhaul on the program to
solve the problem. The main loop turned into something more like:

while (<RECORDS>) {
chomp;
@values = split /\t/, $_;
for ($i=1; $i <= $NUMQUESTIONS; $i++)
my $v = shift @values;
$count[$i]{$v}++
}
}

Of course, the actual code was much longer and much more obfuscated,
although it was nither as long nor as obfuscated as when I got to work
on it.

I shudder to think what would have happened to this program if one of
the responses had been named `i' or `v' or `3' or some such. One can
even imagine that that happened once upon a time, and the reponse was
to change the name instead of taking the warning.

Anyway, deriving the name of the variable from an input value turned
out to be a very stupid decision in this case, and one which cost my
client a couple of thousand dollars.

When people come into comp.lang.perl.misc asking how to do something
stupid, I'm never quite sure what to do. I can just answer the
question as asked, figuring that it's not my problem to tell people
that they're being stupid. That's in my self-interest, because it
takes less time to answer the question that way, and because someone
might someday pay me to clean up after their stupidity, as happened in
this instance. But if I do that, people might jump on me for being a
smart aleck, which has happened at times. (``Come on, help the poor
guy out; if you know what he really need why don't you just give it to
him?'')

On the other hand, I could try to answer on a different level, present
a better solution, and maybe slap a little education on `em. That's
nice when it works, but if it doesn't it's really sad to see your hard
work and good advice ignored. Also, people tend to jump on you for
not answering the question. (``Who are you to be telling this guy
what he should be doing? Just answer the question.'')

I guess there's room for both kinds of answer. Or maybe there isn't
room for either kind.

Whatever. I seem to have gone off on a tangent. The real root of the
problem code is: It's fragile. You're mingling unlike things when you
do this. And of two of those unlike things happen to have the same
name, they'll collide and you'll get the wrong answer. So you end up
having a whole long list of names which you have to be careful not to
reuse, and if you screw up, you get a very bizarre error. This is
precisely the problem that namespaces were invented to solve, and
that's just what a hash is: A portable namespace.

The main point of this article was to present a real example of a case
where using a variable as a variable name was a really stupid thing to
do. Since most of the people who post about that in
comp.lang.perl.misc seem to be trying to do the same stupid thing in
the same stupid way, I thought I'd mention it, and maybe raise the
general awareness of this problem.


Zenin

unread,
Jun 11, 1998, 3:00:00 AM6/11/98
to

Mark-Jason Dominus <m...@op.net> wrote:
>snip<
: The main point of this article was to present a real example of a case

: where using a variable as a variable name was a really stupid thing to
: do.
>snip<

But just don't forget that you can do it when you need to. There
are valid reasons to use soft refs, it's just that most of them
are at the wizard level.

Always, always use strict. If you have a small piece that needs
soft refs, subs, etc then mark it as such:

use strict;
{
no strict 'refs'; # eg, warning: we are doing funky things here
...magic only goes here...
}

--
-Zenin
ze...@archive.rhps.org

Tom Christiansen

unread,
Jun 11, 1998, 3:00:00 AM6/11/98
to

[courtesy cc of this posting sent to cited author via email]

In comp.lang.perl.misc, m...@op.net (Mark-Jason Dominus) writes
one of the best articles I've read this week.

:When people come into comp.lang.perl.misc asking how to do something


:stupid, I'm never quite sure what to do. I can just answer the
:question as asked, figuring that it's not my problem to tell people
:that they're being stupid.

I guess

$dirsize = -s $directory;

is one of those, eh? :-)

I certainly strongly agree that trying to use a variable to store a
variable *by name* rather than by reference is something crying out for
a hash. Then again, so are a lot of thing in Perl, like uniquing lists,
checking existence, etc. I think using hashes as a fundamental way of
looking at a problem is one of the big hurdles for many people coming to
Perl from anything but awk, python, icon, or those cool snobolish things.

Another is of course regular expressions.

--tom
--
"You can't have filenames longer than 14 chars.
You can't even think about them!"
--Larry Wall in Configure from the perl distribution

Alan K. Jackson

unread,
Jun 11, 1998, 3:00:00 AM6/11/98
to

In article <6lnb70$lct$1...@monet.op.net>, Mark-Jason Dominus wrote:
>
> People show up in comp.lang.perl.misc all the time asking how to use
> the contents of a variable as the name of another variable. For
> example, they have $foo = 'snonk', and then they want to operate on
> the value of $snonk.
> ...bobbit

> When people come into comp.lang.perl.misc asking how to do something
> stupid, I'm never quite sure what to do. I can just answer the
> question as asked, figuring that it's not my problem to tell people
> that they're being stupid. That's in my self-interest, because it
> takes less time to answer the question that way, and because someone
> might someday pay me to clean up after their stupidity, as happened in
> this instance. But if I do that, people might jump on me for being a
> smart aleck, which has happened at times. (``Come on, help the poor
> guy out; if you know what he really need why don't you just give it to
> him?'')
>

Personally I read this newsgroup (and others) not to "get the answer", but
to try to understand the deeper structure of the language. In every
language there is an idiom for doing things, that may not be at all
obvious. I want to learn the idiom, and that is what would be useful
for these folks to learn - whether they know it or not. In Perl, using
hashes instead of using the name of a variable as the contents of a variable
is a key idiom. There may be more than one way to do it, but many of the
ways to do it are wrong-headed and fraught with perils. Good idiomatic
use of a language should produce readable, robust, efficient code.

H.Merijn Brand

unread,
Jun 11, 1998, 3:00:00 AM6/11/98
to

Mark-Jason Dominus wrote:
> :
> :
> The main point of this article was to present a real example of a case
> where using a variable as a variable name was a really stupid thing to
> do. Since most of the people who post about that in
> comp.lang.perl.misc seem to be trying to do the same stupid thing in
> the same stupid way, I thought I'd mention it, and maybe raise the
> general awareness of this problem.

Good point here. There's one point I like to mention in favour of
soft-refs: If you check the name of the softref BEFORE actualy
asigning a value to it, you can use 'reset'.

In a program previously written in RPT that spanned far over 1500
lines of code, rewriting that to perl gave the same possibilities
in less than 50 lines (which now has grown to over 350, but that's
not the point here).

Checking on input lines, data is stored in variables that start with
a letter (well chosen AND documented) that gives them a special
scope to the whole program. Variables starting with i.e. "e" can be
resetted at some level, while "f" variables have a longer life-cycle.

It would be possible to use separate hashes $e{}, $f{} and so on,
but this would greatly decrease legibility. $e010240 does mean a
lot to the people that create the "format" part of the program,
which is required in the main line. People writing and maintaining
those format scripts are likely NEVER to see the mainline NOR the
way `their' variables are created.


Kevin Reid

unread,
Jun 11, 1998, 3:00:00 AM6/11/98
to

Zenin <ze...@bawdycaste.org> wrote:

> Mark-Jason Dominus <m...@op.net> wrote:
> >snip<

> : The main point of this article was to present a real example of a case


> : where using a variable as a variable name was a really stupid thing to
> : do.

> >snip<
>
> But just don't forget that you can do it when you need to. There
> are valid reasons to use soft refs, it's just that most of them
> are at the wizard level.
>
> Always, always use strict. If you have a small piece that needs
> soft refs, subs, etc then mark it as such:
>
> use strict;
> {
> no strict 'refs'; # eg, warning: we are doing funky things here
> ...magic only goes here...
> }

TMTOWTDI. If you want obfuscation, you can also get around "use strict
'refs'" by accessing the symbol table:

$var = "Yup!\n";

print ${$::{'var'}{SCALAR}};

--
Kevin Reid. | Macintosh.
"I'm me." | Think different.

Sean McAfee

unread,
Jun 11, 1998, 3:00:00 AM6/11/98
to

In article <1daflxm.nm...@slip166-72-108-44.ny.us.ibm.net>,
Kevin Reid <kpr...@ibm.net> wrote:

>Zenin <ze...@bawdycaste.org> wrote:
>> Always, always use strict. If you have a small piece that needs
>> soft refs, subs, etc then mark it as such:

>> use strict;
>> {
>> no strict 'refs'; # eg, warning: we are doing funky things here
>> ...magic only goes here...
>> }

>TMTOWTDI. If you want obfuscation, you can also get around "use strict
>'refs'" by accessing the symbol table:

>$var = "Yup!\n";

>print ${$::{'var'}{SCALAR}};

ITYM:

print ${*{$::{'var'}}{SCALAR}};

Or, more succinctly,

print ${$::{'var'}};

<blink> <blink> Wow, I hadn't realized how easy it was to get around 'use
strict'. Only five additional characters, if the variable is in package
'main'.

--
Sean McAfee | GS d->-- s+++: a26 C++ US+++$ P+++ L++ E- W+ N++ |
| K w--- O? M V-- PS+ PE Y+ PGP?>++ t+() 5++ X+ R+ | mcafee@
| tv+ b++ DI++ D+ G e++>++++ h- r y+>++** | umich.edu

0 new messages