Anonymous Monk has asked for the wisdom of the Perl Monks concerning the following question:

Hiya my brothers!

This is really a matter curiousity as much as anything.
I have a bunch of scalar variables I want to set to certain values. Call them:

my ($a, $b, $c, $d);
I've made a subroutine that figures out what those values should be, and puts them in a hash:
my %hash = ( 'a' => 'apple, 'b' => 'banana', 'c' => 'cantaloupe', 'd' +=> 'dice', );
Now, I realize I could simply use the hash in my program, or any number of other solutions, but really I'm just kindof wondering if there is an elegant way to simply iterate through the keys of that hash and assign the variable name, indicated in the key, to the value? So my goal is that $a eq 'apple', for example.??

Replies are listed 'Best First'.
Re: Trying to automate some scalar assignments
by davido (Cardinal) on Sep 22, 2011 at 20:44 UTC

    The following 24 lines of code demonstrate how to do what you're describing (populating lexical "my" variables according to their symbolic names). Symbolic references don't work with lexicals, so string eval is used to inject generated code into your run. As I mentioned, the example is twenty four lines long, and I would bet that in short order people here could come up with two dozen reasons why this shouldn't be done. But injecting code into the runtime via string eval is occasionally used to accomplish tricks that you can't easily accomplish any other way. You don't have to look any further than Memoize (which I think is from the Perl core distribution) to see an example of using string eval to do something that isn't possible in another way (in that case, it's to dynamically set prototypes on manufactured functions).

    So unless you're intentionally creating some deep magic, or writing a PerlMonks post, you probably ought to just forget about this:

    use strict; use warnings; use v5.12; my ( $a, $b, $c, $d ); my %hash = ( 'a' => 'apple', 'b' => 'banana', 'c' => 'cantaloupe', 'd' => 'dice', ); my $n = 1; foreach my $symbol ( keys %hash ) { say "Iteration ", $n++, ": $symbol => $hash{$symbol}"; say "\tExecuting as follows: \$$symbol = \$hash{\$symbol}\n"; eval "\$$symbol = \$hash{\$symbol}"; # <--------- The evil. } foreach my $symbol ( qw/a b c d/ ) { say "\$$symbol now contains ", eval "\$$symbol"; # Once we start the evil it's hard to stop. }

    And the output...

    Iteration 1: c => cantaloupe Executing as follows: $c = $hash{$symbol} Iteration 2: a => apple Executing as follows: $a = $hash{$symbol} Iteration 3: b => banana Executing as follows: $b = $hash{$symbol} Iteration 4: d => dice Executing as follows: $d = $hash{$symbol} $a now contains apple $b now contains banana $c now contains cantaloupe $d now contains dice

    I won't enumerate the twenty four reasons (or more) why this isn't a good idea. But I will offer this: If you think you've got one of those situations where it's a good idea, go take a vacation or something; you're working too hard. Memoize is a pretty special case module. There are other special cases out there too. But if you were to start doing this in every day code you'll be pouring fuel on the fires of hell such that its pitchstone gates fail to contain them, thus endangering our mortal realm.

    If Edsger Dijkstra were alive today he might write an article that Niklaus Wirth would rename, "String eval Considered Harmful." Just as with goto, despite its problems, there are times when it's still useful, though potentially far more harmful.


    Dave

      Oh come on...if you're going to muck with symbolic references, let's muck with symbolic references (and the symbol table) (-:
      my %hash = (a => 1, b => 2, c => 3, d => 4); for (keys %hash) { *$_ = \$hash{$_}; } $hash{c} = "foobar"; print "$c\n";
      (Caveat: This does not use 'my' variables, but then, the OP didn't say that they were required)

        Well that's run-of-the-mill evil. :)

        I did consider the global symbol table, but the first line of sample code provided by the OP was, "my($a, $b, $c, $d);", so I assumed he really was trying to manipulate lexicals symbolically. Either way we're both going to need to wash our hands in hot water with pumice soap now.


        Dave

Re: Trying to automate some scalar assignments
by Util (Priest) on Sep 22, 2011 at 19:14 UTC
    You can get all the values at once, by using a hash slice.
    my %hash = (a=>'apple',b=>'banana',c=>'cantaloupe',d=>'dice'); my ( $a, $b, $c, $d ) = @hash{ qw( a b c d ) };