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

I am new to use strict, and tired of being flamed for not using it. so, I am attempting to write a script that... uses strict! my problem lies with a variable scope that I cant figure out. On line 10 of the following script I have an "unless" statement. The script ran fine, untill I wrapped that line of code inside the unless. Once I wrapped it, I apparently lost scope of the $cfg variable... I tried replacing "my $cfg" with our, and local $cfg. Obviously neither of those worked.. What is the correct way to do this???
#!/usr/local/bin/perl -w use strict; use Config::Simple; my $config_file = shift; if (!$config_file) { $config_file = "etc/allweb-backup.conf"; } unless (my $cfg = new Config::Simple($config_file)) { print "CRITICAL: $config_file is not a valid INI file!\n"; } my %Config = $cfg->vars(); print "###############################################\n-CONFIG-: $con +fig_file\n"; while (my($key,$val) = each %Config) { if (!$val) { print "WARNING : $key has NULL value!\n"; my $count++; }else { print "OK : $key has value of $val\n"; } } print "#########################################\ndone.\n";
  • Comment on For the life of me, i can't figure out this "use strict" variable problem
  • Download Code

Replies are listed 'Best First'.
Re: For the life of me, i can't figure out this "use strict" variable problem
by Golo (Friar) on Oct 24, 2004 at 20:49 UTC
    do either
    my $cfg; unless ($cfg = new Config::Simple($config_file)) { print "CRITICAL: $config_file is not a valid INI file!\n"; }
    or just
    my $cfg = new Config::Simple($config_file) or print "CRITICAL: $config_file is not a valid INI file!\n";
    Your $cfg goes out of scope if you define it within the brackets.
    You also probably want to die instead of print if that is a critical error.
      Ahhh ok. I thought that I would no longer be able to call $cfg once inside the 'unless'.. Well that fixed the problem. Thank you. I still have another problem specific to this module.. maybe youve seen something simular before. here is my current code
      #!/usr/local/bin/perl -w use strict; use Config::Simple; my $config_file = shift; if (!$config_file) { $config_file = "etc/allweb-backup.conf"; } my $cfg = new Config::Simple($config_file); my (%Config); unless (%Config = $cfg->vars()) { die "CRITICAL: $config_file is not a valid INI file!\n"; }
      I tried the unless statement wrapped around the $cfg line, and that gave me an error.. In the above I wrapped my unless around the %Config line, that also gave the same error.. I guess neither is returning false when it craps out. Any idea how I can get it to die and print my message instead of the message in the module... this is the error message I get when running this code.
      Something went wrong. No supported configuration file syntax found at +/usr/local/lib/perl5/site_perl/5.8.2/Config/Simple.pm line 184, <FH> +line 16.
        thats most likely because you cannot call $cfg->vars() if your Config::Simple object could not be created (although, the error message doesn't match to your example code).

        You should check for and handle the error on the line you create the Config::Simple object (no later):
        my $cfg = new Config::Simple($config_file) or die "aaarg $!";
        You need eval:
        eval { %Config = $cfg->vars() }; if($@) { die "CRITICAL: $config_file is not a valid INI file!\n" }
        Unrelated to your scoping issue (once again it's been answered well by others before this) but there's a Perl idiom for this tidbit of code:
        my $config_file = shift; if (!$config_file) { $config_file = "etc/allweb-backup.conf"; }
        which is a simple: my $config_file = shift || "etc/allweb-backup.conf"; Same results, cleaner code (IMHO).
        I thought that I would no longer be able to call $cfg once inside the 'unless'

        You seem to have figured this out, but I'd just like to reinforce the point. Scalar variables are accessible from inner scopes, but not from outer scopes. So if you scope a variable in the top-level of a subroutine, then any nested blocks (if statements, while loops, etc) will have access to the variable. But anything outside of the subroutine will not. Here's the obligatory code example:

        sub foo { my $foo = 1; if (1 == 1) { # just to demonstrate the point $foo++; # inside foo, works fine } print $foo; bar(); } sub bar { print $foo; # outside foo, blows up } foo();

        Also keep in mind that the inner/outer determination is done "physically". That is, it's not based on the call stack. It's based on the location in the actual code. This is different from dynamic scoping (i.e. local in Perl), which is based on the execution path. For this reason, lexical scoping is much more predictable and understandable. Here's an example:

        sub foo { local $foo = 1; if (1 == 1) { # just to demonstrate the point $foo++; } print "From foo: $foo\n"; bar(); } sub bar { # this variable will be set to whatever it was # before we got called print "From bar: $foo\n"; } $foo = 5; foo(); bar();