Beefy Boxes and Bandwidth Generously Provided by pair Networks
go ahead... be a heretic
 
PerlMonks  

eval not behaving like I expected... why?

by blue_cowdawg (Monsignor)
on Mar 13, 2006 at 21:11 UTC ( [id://536380]=perlquestion: print w/replies, xml ) Need Help??

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

Drawing inspiration from a couple of different sources I decided to try something and it doesn't work quite like I expected it to.

Heres the deal. I have a data file as such:

my $fee="FEE" my $fi="FI" my $fo="FO" my @fum=qw / fee fi fo fum /
and I have a very simple Perl script as such:
use Data::Dumper; use warnings; open(DAT,"< datafile.txt") or die $!; while (my $line=<DAT>){ chomp $line; eval $line; if ($@){ print $@; } } print Dumper($main::fee,$fi,$fo,@fum);

That's not the code I started off with, it is pretty much what it morphed into as I tried to make this thing work. What I was expecting to have happen was the variables  $fee,$fi,$fo and @fum to be defined as a result of reading in the data file and feeding each line through eval. Reading the perldoc eval and looking at the man page for Inline::Files of all things led me to believe this should work. Part of my inspiration was to come up with a clever answer to this question and so far I've failed to using this method. And indeed a strange thing happened on the way to enlightenment.

New before you yell at me, I know I don't have use strict; in there. That was by choice as part of my intellectual excersize. When the code runs I see the following:

perl loadData.pl Name "main::fum" used only once: possible typo at loadData.pl line 15. Name "main::fo" used only once: possible typo at loadData.pl line 15. Name "main::fi" used only once: possible typo at loadData.pl line 15. Name "main::fee" used only once: possible typo at loadData.pl line 15. $VAR1 = undef; $VAR2 = undef; $VAR3 = undef;
In one set of lines I'm being told the the variables are only being used once during the scope and the other set are telling me the variables are not being set at all! Huh?

So, I turn on strict to dig at this further and I see:

[pberghol@cowdawg ext-files]$ perl loadData.pl Global symbol "$fi" requires explicit package name at loadData.pl line + 16. Global symbol "$fo" requires explicit package name at loadData.pl line + 16. Global symbol "@fum" requires explicit package name at loadData.pl lin +e 16. Execution of loadData.pl aborted due to compilation errors.
OK.. I'm seeing compile time errors... that makes sense.. sorta... Let's dig ourselves deeper and set the package names for all those variables. I'm back to the same complaints again:
perl loadData.pl Name "main::fum" used only once: possible typo at loadData.pl line 16. Name "main::fo" used only once: possible typo at loadData.pl line 16. Name "main::fi" used only once: possible typo at loadData.pl line 16. Name "main::fee" used only once: possible typo at loadData.pl line 16. $VAR1 = undef; $VAR2 = undef; $VAR3 = undef;

What in the world is going on here?

Replies are listed 'Best First'.
Re: eval not behaving like I expected... why?
by ChemBoy (Priest) on Mar 13, 2006 at 21:22 UTC

    I think you're forgetting that my produces a lexical variable that isn't attached to a package namespace. Since you're creating them inside a string eval, they go out of scope as soon as it ends, leaving you with the same variables you had when you entered that string eval (that is, none).

    For a quick strict-compliant fix, change all of your mys to ours—alternatively, use vars qw($fee $fi $fo @fum); and dropping the my entirely would have a similar effect.



    If God had meant us to fly, he would *never* have given us the railroads.
        --Michael Flanders

          I think you're forgetting that my produces a lexical variable that isn't attached to a package namespace.

      That being the case, (and I'm agreeing with you) why does this work?

      use Inline::Files; use Data::Dumper; open CACHE or die $!; # read access (uses $CACHE to locate file) eval join "", <CACHE>; close CACHE or die $!; print "\$var was ’$var’\n"; while (<>) { chomp; $var = $_; print "\$var now ’$var’\n"; } open CACHE, ">$CACHE" or die $!; # write access print CACHE Data::Dumper->Dump([$var],['var']); close CACHE or die $!; __CACHE__ $var = 'old value';
      That's ripped right from the man page for Inline::Filss and it works! Try it!


      Peter L. Berghold -- Unix Professional
      Peter -at- Berghold -dot- Net; AOL IM redcowdawg Yahoo IM: blue_cowdawg

        The lack of my in the __CACHE__ section has a lot to do with that...

Re: eval not behaving like I expected... why?
by blokhead (Monsignor) on Mar 13, 2006 at 21:23 UTC
    Your eval statement declares several lexical variables, but then you expect them to be available via the symbol table as globals! That won't work, just as the following won't work:
    my $foo = "blah"; print $main::foo; ## whoops, not the same variable
    In addition, eval creates a fresh lexical scope, so the scope of the lexical variables is only within that eval. You can't get such a thing to work with lexicals + eval:
    eval 'my $foo = 1'; print $foo; ## whoops, outside of $foo's scope
    It defeats one of the major purposes of lexical variables (that is, compile-time checking of variable bindings). You'll have to use either globals, or perhaps a hash of values if you want to instantiate variables via eval (and have them visible from outside the eval).

    blokhead

Re: eval not behaving like I expected... why?
by Crackers2 (Parson) on Mar 13, 2006 at 21:18 UTC

    You're declaring your variables with my, so as soon as you leave the eval block they go out of scope.

    I just tested it to be sure, and if you just remove the "my" from each line in the datafile, things will behave as you expect. Of course under strict you'd still get the "Global symbol ... requires explicit package name at ./rf line ..." errors unless you declare them somewhere.

          You're declaring your variables with my, so as soon as you leave the eval block they go out of scope.

      Good thought... taking the "my" out now gives the following spew:

      $ perl loadData.pl Name "main::fum" used only once: possible typo at loadData.pl line 16. Name "main::fo" used only once: possible typo at loadData.pl line 16. Name "main::fi" used only once: possible typo at loadData.pl line 16. Name "main::fee" used only once: possible typo at loadData.pl line 16. Variable "$fee" is not imported at (eval 1) line 1, <DAT> line 1. Global symbol "$fee" requires explicit package name at (eval 1) line 1 +, <DAT> line 1. Variable "$fi" is not imported at (eval 2) line 1, <DAT> line 2. Global symbol "$fi" requires explicit package name at (eval 2) line 1, + <DAT> line 2. Variable "$fo" is not imported at (eval 3) line 1, <DAT> line 3. Global symbol "$fo" requires explicit package name at (eval 3) line 1, + <DAT> line 3. Variable "@fum" is not imported at (eval 4) line 1, <DAT> line 4. Global symbol "@fum" requires explicit package name at (eval 4) line 1 +, <DAT> line 4. $VAR1 = undef; $VAR2 = undef; $VAR3 = undef;
      Following that thought one step further, let's declare them as "our." Run the code and we still see spew, but not as severe:
      $ perl loadData.pl Name "main::fum" used only once: possible typo at loadData.pl line 16. Name "main::fo" used only once: possible typo at loadData.pl line 16. Name "main::fi" used only once: possible typo at loadData.pl line 16. Name "main::fee" used only once: possible typo at loadData.pl line 16. $VAR1 = 'FEE'; $VAR2 = 'FI'; $VAR3 = 'FO'; $VAR4 = 'fee'; $VAR5 = 'fi'; $VAR6 = 'fo'; $VAR7 = 'fum';

      I guess in the end that means that you have to pre-declare the variables before reading in the "configuration file" and getting the values defined. Not pretty... but it works. I like the way I normally do it better. Which is to sey I either create a module and export my values or I use something like XML::Simple to do the dirty work.

Re: eval not behaving like I expected... why?
by jdporter (Paladin) on Mar 14, 2006 at 12:28 UTC

    Other folks have helped you figure out your perl/syntax issues, but I think there's a more fundamental issue + solution.

    If you're going to have your config file be executable perl code that sets some variables, at least one of the following conditions should hold:

    1. the variable names are known a priori to the calling code.
    2. the variables live in a namespace — and there is no ambiguity as to what that namespace is.

    In the first case, you can declare the variables with my in the calling code; that solves the problems you were having.

    In the second case, you can write your config variables like so:

    $config::fee="FEE" $config::fi="FI" $config::fo="FO" @config::fum=qw / fee fi fo fum /

    Of course, that means that the variables are global, rather than lexicalized to the scope of the caller.

    To get a little more fancy with that approach, you could insert a dynamically decided namespace into the assignments before eval'ing:

    my $namespace = "here"; while (<DAT>) { s/([\$\@\%])/$1$namespace\::/; eval $_; }

    But if you really want to go the lexical route, my personal inclination would be to store all the config variables in a single anymous hash:

    # config: { fee=>"FEE", fi=>"FI", fo=>"FO", fum=>[qw/ fee fi fo fum /], }
    then just eval the file as a whole:
    my $config_hr = do 'datafile.txt';

    If you're trying to keep it simple for the sake of some non-programmers who'll have to be maintaining these config files, I respectfully suggest that you abandon the eval'able code approach altogether, and use one of the solutions already created to address this concern. Please take a look at a short list of config file modules.

    We're building the house of the future together.

Log In?
Username:
Password:

What's my password?
Create A New User
Domain Nodelet?
Node Status?
node history
Node Type: perlquestion [id://536380]
Approved by Corion
help
Chatterbox?
and the web crawler heard nothing...

How do I use this?Last hourOther CB clients
Other Users?
Others avoiding work at the Monastery: (3)
As of 2024-04-20 02:10 GMT
Sections?
Information?
Find Nodes?
Leftovers?
    Voting Booth?

    No recent polls found