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

I'm currently in a situation in which I need to create variables whose names are determined by other variable values. (this is to support older code which relies on those variables having those names while moving to a new architecture in which the info is stored in a db.

I have:

my $test="my_variable_name"; #imagine this is a hash key my $default_value="the value I set"; #while this is the hash value eval("\$$test = '$default_value';"); print "the value of \$my_variable_name = $my_variable_name\n"; $my_variable_name = "A new value"; print "the value of \$my_variable_name = $my_variable_name\n";

So far, so good. That works.

I'm fairly certain that there is a Better(tm) way to do this using symbol table manipulation, but I'm not sure how to go about it. I've tried all of:

my $test="my_variable_name"; my $default_value="the value I set"; *$test = $default_value; #*{$test} = $default_value; #*{"$test"} = $default_value; #*{"$test"} = \$default_value; #*{"$test"} = \&default_value; print "the value of \$my_variable_name = $my_variable_name\n"; $my_variable_name = "A new value"; print "the value of \$my_variable_name = $my_variable_name\n";

none of which work. (all commented lines have been tried).

Any pointers would be appreciated. Thanks

Replies are listed 'Best First'.
Re: symbol table vs. eval
by chargrill (Parson) on Feb 23, 2006 at 18:30 UTC

    This will do what you want, I think:

    my $test="my_variable_name"; my $default_value="the value I set"; $$test = "old value"; print "the value of \$my_variable_name = $my_variable_name\n"; $my_variable_name = "A new value"; print "the value of \$my_variable_name = $my_variable_name\n";

    ... but don't do that :)

    Update: Perhaps I read & posted too quickly, does this do what you want?

    my $test="my_variable_name"; my $default_value="the value I set"; $default_value = *$test; $$default_value = "old value"; print "the value of \$my_variable_name = $my_variable_name\n"; $my_variable_name = "A new value"; print "the value of \$my_variable_name = $my_variable_name\n";

    Update2: Thanks ikegami. You'll notice I omitted the obligatory "use strict;" and "use warnings;", because when they're not omitted:

    $ perl symbol.pl Global symbol "$my_variable_name" requires explicit package name at sy +mbol.pl line 12. Global symbol "$my_variable_name" requires explicit package name at sy +mbol.pl line 13. Global symbol "$my_variable_name" requires explicit package name at sy +mbol.pl line 14. Execution of symbol.pl aborted due to compilation errors.


    --chargrill
    $/ = q#(\w)# ; sub sig { print scalar reverse join ' ', @_ } + sig map { s$\$/\$/$\$2\$1$g && $_ } split( ' ', ",erckha rlPe erthnoa stJu +" );

      A clear case of my overthinking the problem. Your first example does what I am needing. However I wonder if you can explain why the following occurs:

      Code:
      package apackage; my $test="my_variable_name"; my $default_value="the value I set"; $$test = $default_value; print "the value of \$my_variable_name = $my_variable_name\n"; package main; $my_variable_name = "A new value"; print "the value of \$my_variable_name = $my_variable_name\n"; print "the value of the package variable = $apackage::my_variable_name +\n";
      Output:
      the value of $my_variable_name = the value I set the value of $my_variable_name = A new value the value of the package variable = the value I set

      which works and is what I need,

      but...

      Code:
      package apackage; my $test="my_variable_name"; my $default_value="the value I set"; our $$test = $default_value; print "the value of \$my_variable_name = $my_variable_name\n"; package main; $my_variable_name = "A new value"; print "the value of \$my_variable_name = $my_variable_name\n"; print "the value of the package variable = $apackage::my_variable_name +\n";
      Output:
      Can't declare scalar dereference in our at -e line 5, near "$test =" Execution of -e aborted due to compilation errors.

        You need to use our $my_variable_name; You may thing hardcoding the name is a problem, but it's not. The only reason you need our is because you hardcoded the name in the print. For example,

        use strict; use warnings; package Hack; sub slash { my $var_ref = do { no strict 'refs'; \${'ExistingPackage::var'} }; $$var_ref = 'bar'; } package main; ExistingPackage->print_it(); Hack->slash(); ExistingPackage->print_it();
        whether ExistingPackage is
        use strict; use warnings; package ExistingPackage; our $var = 'foo'; sub print_it { print("$var\n"); } 1;
        or
        package ExistingPackage; $var = 'foo'; sub print_it { print("$var\n"); } 1;

        Hrm. Note where I declare vars:

        package apackage; my $test="my_variable_name"; my $default_value="the value I set"; $$test = $default_value; print "the value of \$my_variable_name = $my_variable_name\n"; package main; $my_variable_name = "A new value"; our $test; print "the value of \$my_variable_name = $my_variable_name\n"; print "the value of the package variable = $apackage::my_variable_name +\n";

        Yields:

        the value of $my_variable_name = the value I set the value of $my_variable_name = A new value the value of the package variable = the value I set


        --chargrill
        $/ = q#(\w)# ; sub sig { print scalar reverse join ' ', @_ } + sig map { s$\$/\$/$\$2\$1$g && $_ } split( ' ', ",erckha rlPe erthnoa stJu +" );
      Caveat: Your solution won't work if $my_variable_name is a lexical (my) variable. It will only work if it's a package (our) variable.
        I am working with package variables, so in this case I'm OK, but I do wonder why I can't declare it using 'our' (see my post below). Thanks!

      Concerning your update, strict has nothing to do with it. If use strict is already present, so is either our $my variable_name; or my $my variable_name;. I was saying your code will only work with the former, not the latter. The OP's code (and the code in my reply) works with both.

Re: symbol table vs. eval
by Roy Johnson (Monsignor) on Feb 23, 2006 at 18:31 UTC
    Lexical (my) variables are not stored in the symbol table. You could, however, make a hash of references to the variable names. Then, with some dereferencing,
    my $test="my_variable_name"; #imagine this is a hash key my $default_value="the value I set"; #while this is the hash value my %hash = ($test => \$default_value); print "the value of \$$test = ${$hash{$test}}\n"; ${$hash{$test}} = "A new value"; print "the value of \$$test = ${$hash{$test}}\n";
    I'm not sure this demonstrates what you want to do, but hopefully it gives you an idea about how to approach it.

    Caution: Contents may have been coded under pressure.
Re: symbol table vs. eval
by ikegami (Patriarch) on Feb 23, 2006 at 18:48 UTC

    You can make your code safer by replacing
    eval("\$$test = '$default_value';");
    with
    ${eval('\$' . $test)} = $default_value;
    For example, it will work even if the value in $default_value contains the character '.