[Techtalk] Perl Frustration

Almut Behrens almut-behrens at gmx.net
Fri Oct 31 20:19:42 EST 2003


On Thu, Oct 30, 2003 at 06:09:57PM -0800, Kai MacTane wrote:
> 
> I want to declare a set of variables inside a loop, and have them be 
> accessible to the rest of the program. It's not known until run-time just 
> how many of these variables there are, or what their names will be.
> (...)
> 
> print "Enter names of some variables (blank to finish)...\n";
> my $thisline;
> 
> chomp($thisline = <STDIN>);
> while ($thisline =~/\w/) {
>     $foovar = $thisline.'_foo';
>     $$foovar = $thisline;
>     chomp($thisline = <STDIN>);
> }

On Fri, Oct 31, 2003 at 01:50:28AM -0800, Kai MacTane wrote:
> 
> At least one of the script in question is already released (see 
> http://www.gothpunk.com/~kmactane/software/mlm-command), and some of the 
> variables I'm looking at need to be available as actual variables. Either 
> that, or I'll have to do some ugly hacking to keep the script's behavior 
> the same. Or else just change the behavior, and the documentation.
> 
> I also thought, "Hey, I can just have them all be keys in a hash!" Then I 
> looked at the docs again, and realized that wasn't going to do it. I 
> essentially need to take some dynamically-input variables (let's say foo, 
> bar and wombat), and wind up having $foo_extra, $bar_extra and 
> $wombat_extra be available globally by the end of the script.
> 
> Is it possible?


the feature you're using here to define new variables at runtime is
named "symbolic references", and those in principle do not work with
my-variables (reason is, among others, that my-vars have no associated
symbol table). So, if you want to "use strict" (which by default does
not allow symbolic refs), I think you basically only have the following
two options:

(1) locally disable strict checking for the symbolic references:

  use strict;
  
  print "Enter names of some variables (blank to finish)...\n";
  my $thisline;
  
  chomp($thisline = <STDIN>);
  while ($thisline =~/\w/) {
      no strict 'refs';   # allow symbolic refs for the next two lines
      $main::foovar = $thisline.'_foo';
      $$main::foovar = $thisline;
      use strict 'refs';
      chomp($thisline = <STDIN>);
  }

this can, btw, also be written somewhat shorter as follows, not
requiring the intermediate variable $foovar

  chomp($thisline = <STDIN>);
  while ($thisline =~/\w/) {
      no strict 'refs';
      ${"main::${thisline}_foo"} = $thisline;
      use strict 'refs';
      chomp($thisline = <STDIN>);
  }


(2) use eval to define the new variables at runtime:

  use strict;
  
  print "Enter names of some variables (blank to finish)...\n";
  my $thisline;
  
  chomp($thisline = <STDIN>);
  while ($thisline =~/\w/) {
    eval "\$main::${thisline}_foo = '$thisline'";
    chomp($thisline = <STDIN>);
  }

The latter can at times become somewhat tricky on the right hand side
of the assignment you need to eval (quoting issues) -- though in this
particular case you should be fine, as the value of $thisline would
have to be a valid variable name anyway...

Also, note that, in all cases you need to fully qualify the variable
names (i.e. prefix them with "main::", or whatever package they're in),
if you cannot predeclare them.


Cheers,
Almut



More information about the Techtalk mailing list