Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

making runtime variable names global in perl

OK, I've looked hard and have tried a myriad of variations to get this to work. I need some help from the perl experts.

First of all, I know, I know, don't use dynamic variable names! Well, I think I need to do so in this case. I'm fixing an inherited script. It has a set of variables that are formed with prefix + "_" + suffix. This started small, but prefix is now a list of about 20 and suffix of about 50 -- a thousand different variables.

The script in some cases loops over these variables, using eval to retrieve an individual value, etc.. This all works. The problem is, all uses of the different variables throughout the script, whether inside a loop on the prefix and/or suffix or just a hardcoded use, assume that these variables are globalized by using use var qw($varname). The number of use vars hardcoded statements has grown out of control. Moreover, there are thousands of past input profile files that initialize these variables using global syntax, all of which need to continue to work.

I was hoping I could improve maintainability by doing the globalization step in a loop, dynamically creating the variable names one at a time, then globalizing them with use vars or our. Here is some code to show what I'm after. I've shown several options here, but each is actually a separate trial. I have tried other variations and cannot keep them straight anymore.

my @prefixes   = ("one", "two", ..., "twenty");
my @suffixes   = ("1", "2", ..., "50");
my $globalvars = "";
for my $suffix (@suffixes) {
    for my $prefix (@prefixes) {
        # option 1 -- remainder of #1 outside of loop
        # NOTE: 1.a (no comma); 1.b (include comma between vars)
        $globalvars .= "\$$prefix\_$suffix, ";

        # option 2
        eval "use vars qw(\$$prefix\_$suffix)";

        # option 3
        my $g = "$prefix\_$suffix";
        eval ("use vars qw(\$$g)");

        # option 4
        eval ("our \$$g");
    }
}

# option 1.a
use vars qw($globalvars);
# or option 1.b
my (eval "$globalvars");
:
:
:
# now use them as global variables
if ($one_1 eq ...) {
    if ($one_10) {

It seems that the problem with "use vars" (besides the fact that it is discouraged) is that the string inside qw has to be the actual variable name, not a dynamic variable name. The 'eval' options don't work, I think, because the scope only exists within the eval itself.

Is there a way to do this in perl?

like image 805
Derek Whistlethorpe Avatar asked Dec 19 '22 03:12

Derek Whistlethorpe


2 Answers

string inside qw has to be the actual variable name, not a dynamic variable name

That's how qw works, it quotes words, it does no interpolation. You don't have to use qw with use vars, though.

#! /usr/bin/perl
use warnings;
use strict;

my @global_vars;
BEGIN { @global_vars = qw($x $y) }
use vars @global_vars;

# strict won't complain:
$x = 1;
$y = 2;

BEGIN is needed here, because use vars runs in compile time, and we need @global_vars to be already populated.

like image 190
choroba Avatar answered Jan 02 '23 11:01

choroba


There's no need for eval EXPR since there's no need to use qw. qw is just one way to create a list of strings, and one that's not particularly useful to your needs.

my @prefixes;  BEGIN { @prefixes = qw( one two ... twenty ); }
my @suffixes;  BEGIN { @suffixes = 1..50; }

use vars map { my $p = $_; map { '$'.$p.'_'.$_ } @suffixes } @prefixes;
like image 30
ikegami Avatar answered Jan 02 '23 11:01

ikegami