r.joseph has asked for the wisdom of the Perl Monks concerning the following question:

OK, here is something I have never really been able to understand very well. Say I am running through a file, and I use a regex to match a certain condition:
while (<FILE>) { if (/.../) { ... } }
(The ... are not intended to be perl operators, they just mean 'something else goes here').
Easy enough. Now say that in the regex in the if(), we use parens to pull two strings, which are then assigned to $1 and $2, obviously. Now lets also say that as we run through this file, we use another regex to find a different pattern, which then matches another string ($1 again), which is then assigned to a global varible called, oh, '$stuff'. So here is the whole situation, pretty much:
my $stuff; while (<FILE>) { if (/(...)(...)/) { # we have $1 and $2 in here, both some string } elsif (/(...)/) { $stuff = $1; } }
(Obviously, this is all psuedo-code because my actual code is very messy and would not suffice for this discussion, but you get the idea.) Now here is where I get stuck. In the if() clause above (where $1 and $2 are assigned) I want to assign a hash value on the fly. Here is what I want to do (assume that anytime we are in the if(), $stuff has a value that was already assigned in the elsif() - in my code, it has to happen this way):
eval "\$$stuff{$1} = $2";
but as you can imagine, this does not in fact work. Now, I have never really been good at the whole reference thing and dynamic varible creation and such, so could someone please explain to me how I would do what I have illustrated above? I have a feeling that it is in fact a rather simple solution, but I continualy find myself up against a wall in this area!

Thanks so much,
R.Joseph

Replies are listed 'Best First'.
Re (tilly) 1: Creating on-the-fly hashes?
by tilly (Archbishop) on Jan 08, 2001 at 08:50 UTC
    First of all what you are heading for looks like it is exactly what Dominus warned against here. (I suggest reading parts 2 and 3.)

    Your actual question is answered by just using a hash:

    $stuff{$1} = $2;

    A deeper point though. If your code has (by your own admission) complex logic and complex conditions then there are good odds that if you step back and rethink it you can find ways to simplify. Try to do that.

    Clean code isn't just aesthetic. Most of the money that will be spent on your code is spent in maintainance. Is the logic so messy that it would be hard for someone who did not know the code to figure it out and fix a bug or add a new feature? If so then how hard will it be for you in a month to fix bugs people find or deal with a changing spec?

      Says tilly:
      First of all what you are heading for looks like it is exactly what Dominus warned against here.

      What he's doing is even worse than the stuff I was warning against. I've been meaning to write a Part 4 in that series that discusses eval. Someone showed up in clpm once and said that his original try (with symbolic references) hadn't worked because strict was on, but he'd goitten around it by using eval, completely missing that this made the problem worse, not better.

Re: Creating on-the-fly hashes?
by chipmunk (Parson) on Jan 08, 2001 at 09:08 UTC
    I agree with Tilly, that you should be assigning to a hash, rather than using symbolic references.

    That said, the reason your code doesn't work is twofold. First, in "\$$stuff{$1} = $2", $stuff{$1} is interpolated as a value from %stuff, whereas you're trying to use $stuff as a symbolic reference. Second, the values of $1 and $2 are interpolated and then evalled, when the values may not be valid Perl code. (If $2 holds the string '+++++', for example, your eval won't compile.)

    On the one hand, a correct line would be: eval "\$$stuff\{\$1} = \$2"; On the other hand, the eval is unnecessary: ${$stuff}{$1} = $2; On the gripping hand, the symbolic ref is also unnecessary, as previously stated: $values{$stuff}{$1} = $2; I hope that's helpful!

Re: Creating on-the-fly hashes?
by t'mo (Pilgrim) on Jan 08, 2001 at 08:40 UTC

    Why bother with:

    eval

    Instead, just make the assignment:

    $stuff{$1} = $2;