Beefy Boxes and Bandwidth Generously Provided by pair Networks
Pathologically Eclectic Rubbish Lister
 
PerlMonks  

Understanding why strict prevents a use of local

by c (Hermit)
on Oct 19, 2001 at 22:42 UTC ( [id://120107]=perlquestion: print w/replies, xml ) Need Help??

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

My code:

#!/usr/bin/perl -w use strict; my @array = qw(one two three); &one; sub one { local $i; foreach $i(@array) { &two; } } sub two { print "$i\n"; }

when i take use strict; out of the equation, the second subroutine prints out the value of $i for each iteration of the foreach loop. however, useing strict causes perl to complain about needing a global declaration for $i. could someone explain this one to me?

humbly -c

Replies are listed 'Best First'.
Re: Understanding why strict prevents a use of local
by dragonchild (Archbishop) on Oct 19, 2001 at 22:45 UTC
    localizing a variable makes a global variable which has a copy for you. It's like a sort-of-but-not-quite lexical. Hence, strict sees local as a global and complains.

    Use my instead.

    ------
    We are the carpenters and bricklayers of the Information Age.

    Don't go borrowing trouble. For programmers, this means Worry only about what you need to implement.

      Using 'my' in this situation though would require that i pass that value on to the next sub routine wouldnt it? for example:

      #!/usr/bin/perl -w use strict; &one; sub one { my $a = "hello"; &two($a); } sub two { my $a = shift; print $a; }

      i ask simply because this whole exercise is being done for a rather lengthy script i have that makes use of several subroutines, all called from one main sub. i end up passing a fairly long group of variables to each of the other subs

      sub execute { &ccCopy($source,$destination,$host,$error); } sub ccCopy { my $source = shift; my $destination = shift; my $host = shift; my $error = shift; }

      this works, but i was hoping to use 'local' two get rid of these extra lines and try to streamline a bit.

      humbly -c

        The reason that local causes strict to complain is that local does not declare global variables (strict only complains about global variables if you haven't declared them). The purpose of local is to temporarily hide the original value of the global, so that you don't accidentally overwrite a value that the rest of your program is using. Basically, letting you use a global variable as if it were lexical. (Sort of.)

        However, that's not what you want to do. You actually want to access the global value of the variable but you want to declare it, so that strict stops complaining. To do that, remove the locals, and add an our (or use vars for < 5.6) to the beginning of the program:

        #!/usr/bin/perl -w use strict; our $i; # Predeclare $i as a global, so # that strict doesn't complain. my @array = qw(one two three); &one; sub one { foreach $i (@array) { &two; } } sub two { print "$i\n"; }

        That said, global variables are usually a bad idea, especially in large (or "lengthy") programs. You should probably go with dragonchild's hash suggestion, or something.

        bbfu
        Seasons don't fear The Reaper.
        Nor do the wind, the sun, and the rain.
        We can be like they are.

        Why not try something like:
        sub execute { my %argsHash = ( Source => $source, Dest => $destination, Host => $host, Error => $error, ); &ccCopy(\%argsHash); } sub ccCopy { my $args = shift; print "Copy: $args->{Source} to $args->{Dest}\n"; }
        That will do two things:
        1. Clean up your messy-looking code
        2. Make it so you stay out of procedural messes by fooling with global variables. (They're sorta like matches, but for big kids. You still don't want to play with them.)

        ------
        We are the carpenters and bricklayers of the Information Age.

        Don't go borrowing trouble. For programmers, this means Worry only about what you need to implement.

        Hi c,

        In my opinion your comment that this "is being done for a rather lengthy script" says to me that you want to avoid globals at all cost. The comments and snippits of advice of our fellow monks in this case are excellent and will work perfectly fine for you. But just in case you were looking for yet another way to do it...

        --
        http://www.nule.org
Re: Understanding why strict prevents a use of local
by IraTarball (Monk) on Oct 20, 2001 at 01:10 UTC
    Just a comment. BTW I agree with the above comments that you whould avoid globals <e>especially</e> in long scripts.

    But as and aside regarding use vars and  our declarations. I don't believe they are quite equivalent. This might be splitting hairs, but a use vars declaration gives a package variable while an our declaration gives a global disguised as a my variable. This means the scoping is lexical for our variables. The following code

    &decl(); print $variable; sub decl { our $variable = 1; }
    would not compile under strict. $variable is out of scope by the print statement. A use vars qw($variable); line would work however.

    Another implication, if you are using packages to give different name spaces in the same file, a declaration like...

    package one; use vars qw($thing1); our $thing2; #stuff; package main; print "$thing1 and $thing2";
    might not do what you expect. For example not run under strict. The vars variable $thing1 is a package variable, not available to the main package without a $one::thing1 type address. $thing2 however, the our declaration <e>is</e> available to the main package. It's scope is the same as my so is file wide in this sample.

    I didn't get this when I first started using <cod>our</code> so I just wanted to throw it there since it seems to apply to this thread.

    Ira,

    "So... What do all these little arrows mean?"
    ~unknown

Re: Understanding why strict prevents a use of local
by cLive ;-) (Prior) on Oct 20, 2001 at 02:59 UTC
    If you really want a global $i under strict you need to use:
    $::i # implicit, $main::i # explicit
    Either will do, but as others have said, avoid globals if you don't need them. ie:
    #!/usr/bin/perl -w use strict; my @array = qw(one two three); &one; sub one { local $::i; foreach $::i(@array) { &two; } } sub two { print "$::i\n"; }
    works, but I would avoid creating a var if you don't need to. Eg:
    #!/usr/bin/perl -w use strict; my @array = qw(one two three); one(); sub one { foreach (@array) { two($_); } } sub two { print "$_[0]\n"; }

    TIMTOWTDI :)

    cLive ;-)

Log In?
Username:
Password:

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

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

    No recent polls found