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

I feel like this is a really stupid question, but I'm sort of at my wit's end and really hoping someone can point out what it is that I'm missing. I have a subroutine and have some variables that are not in scope as I expected and can't figure out why, any wisdom on what I'm missing would be greatly appreciated

sub make_ap_stanza () { my $policy = $_[0]; my $vsname; my $vsowner; my $owner; my $group; my $regexp; my $volumeset; my $volumeset_owner; print "Policy:$policy\n"; my @attrs = @{ $Policy_HoA{$policy} }; foreach(@attrs){ if(($vsname) = ($_ =~ /vs_name =\s+(.*)/)){ print "VSNAME:$vsname\n"; } elsif(($vsowner) = ($_ =~ /vs_owner =\s+(.*)/)){ print "VSOWNER:$vsowner\n"; } elsif(($filter) = ($_ =~ /filter_name =\s+(.*)/)){ #print "FILTER:$filter\n"; my @attrs = @{ $RegexHoA{$filter} }; foreach(@attrs){ if(($regexp) = ($_ =~ /REGEXP =\s+(.*)/)){ print "REGEXP:$regexp\n"; } elsif(($owner) = ($_ =~ /OWNER =\s+(.*)/)){ print "OWNER:$owner\n"; } elsif(($group) = ($_ =~ /GROUP =\s+(.*)/)){ print "GROUP:$group\n"; } } } } print "foo $vsowner\n"; }

So I declared a bunch of variables in the beginning of the code block, the nested routines populate them, but outside of the foreach loop, the variables are uninitialized???

[test1] change_timeout = 10 comment = foobar logmask = 0xffffff parent = thanos policy = perms policy = foobar queue_depth = 32 supports_hsm = yes path = /test1 Policy:perms REGEXP:image.([0-9]+).([0-9]+) OWNER:ANY GROUP:ANY VSNAME:dyn{2}{1} VSOWNER:root Use of uninitialized value $vsowner in concatenation (.) or string at +./getconf line 395. foo

It looks like no matter how long I stare at this, I just can't understand why my variables are not properly declared

Replies are listed 'Best First'.
Re: scope of variables in a sub
by tobyink (Canon) on Sep 24, 2020 at 00:13 UTC

    Replace this:

    elsif(($vsowner) = ($_ =~ /vs_owner =\s+(.*)/)){ print "VSOWNER:$vsowner\n"; }

    With this:

    elsif ( /vs_owner =\s+(.*)/ ){ $vsowner = $1; print "VSOWNER:$vsowner\n"; }

    Your problem is that $vsowner is being set on one iteration of the loop, but being unset the next time around the loop.

    Fix your other if/elsif checks too.

      Well spotted! Assignment in an if condition is just too smelly for my brain to process.

      Optimising for fewest key strokes only makes sense transmitting to Pluto or beyond

        Assignment in an if is fine if you're doing:

        if ( my $var = something() ) { # use $var here }

        (Ditto while.)

        But if $var has a wider scope, it's probably a bad idea.

        >Optimising for fewest key strokes only makes sense transmitting to Pluto or beyond

        Yup. OP must be doing just this. xD

      DOAH!

      Thanks, I should have seen that. Too little sleep last night, brain fog.

Re: scope of variables in a sub
by choroba (Archbishop) on Sep 24, 2020 at 09:40 UTC
    sub make_ap_stanza () { my $policy = $_[0];

    So, you declare the subroutine with empty prototypes, i.e. as taking no parameters, but then you extract the first parameter.

    See Understand why you probably don’t need prototypes.

    map{substr$_->[0],$_->[1]||0,1}[\*||{},3],[[]],[ref qr-1,-,-1],[{}],[sub{}^*ARGV,3]
Re: scope of variables in a sub
by jwkrahn (Monsignor) on Sep 24, 2020 at 01:31 UTC
    Policy:perms REGEXP:image.([0-9]+).([0-9]+) OWNER:ANY GROUP:ANY VSNAME:dyn{2}{1} VSOWNER:root Use of uninitialized value $vsowner in concatenation (.) or string at +./getconf line 395. foo

    The first time through the outer foreach loop /filter_name =\s+(.*)/ matches so it goes through the inner loop where /REGEXP =\s+(.*)/ and then /OWNER =\s+(.*)/ and then /GROUP =\s+(.*)/ match in turn.

    The second time through the outer foreach loop /vs_name =\s+(.*)/ matches.

    The third time through the outer foreach loop /vs_owner =\s+(.*)/ matches.

    Because of the way you capture the variable data, if the outer loop iterates again the regular expressions will not match and the variable $vsowner will cleared (set to undef).

    Change each if/elsif expression from:

    if ( ( $variable ) = /pattern (.*)/ ) {

    To:

    if ( /pattern (.*)/ ) { $variable = $1;
Re: scope of variables in a sub
by LanX (Cardinal) on Sep 23, 2020 at 23:00 UTC
    You don't show us the input data, which leaves us speculating ...

    My (weak) guess is you have an empty match setting $vsowner to undef at some point.

    What happens if you change .* to .+ ?

    Cheers Rolf
    (addicted to the Perl Programming Language :)
    Wikisyntax for the Monastery

      No difference, the data comes from a database and there are no empty records in the source, you can see the variables it populates, printed inside the foreach loop, and then untouched till it's printed outside the loop where it is uninitialized.

Re: scope of variables in a sub
by GrandFather (Saint) on Sep 23, 2020 at 23:56 UTC
A reply falls below the community's threshold of quality. You may see it by logging in.