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

Re: Re: Understanding why strict prevents a use of local

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


in reply to Re: Understanding why strict prevents a use of local
in thread Understanding why strict prevents a use of local

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

Replies are listed 'Best First'.
(bbfu) (local does not declare) Re(3): Understanding why strict prevents a use of local
by bbfu (Curate) on Oct 19, 2001 at 23:08 UTC

    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.

Re3: Understanding why strict prevents a use of local
by dragonchild (Archbishop) on Oct 19, 2001 at 23:03 UTC
    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.

      i like this solution, however can i add to the hash reference being passed to each subroutine? i ask because my subroutines add to the information being handed down with each nesting:

      #!/usr/bin/perl -w use strict; my $source = "tftp"; my $destination = "run"; &first; sub first { my %argsHash = ( Source => $source, Destination => $destination, ); &second(\%argsHash); } sub second { my $args = shift; my $error = "problems!"; print "This works, but i need to pass the error value to the third subroutine, in addition to $args->{Source} and $args->{Destination}\n"; &third(); }

      its here that i get confused. not only do i need to pass the existing value of $args to the third subroutine, but i also need to pass the value of $error as well. i've tried a little experimenting with &third(\$args); and although its passed, its passed as a scalar rather than a hash it seems. i see that i can add the value of $error within the second subroutine, such as:

      $args->{Error} = $error;

      but i'm stuck on how to pass this new hash to the next subroutine.

      humbly -c

        Ahh, I see why you're confused. It's context again.

        Arguments passed to a subroutine are passed as a list. If you put in a hash, it'll be flattened into a list:

        my %hash = ( one => 1, two => 2, ); foo(%hash); sub foo { print join(' | ', @_), "\n"; }
        You can coerce these arguments into a hash inside your subroutine. It's not often done, though, because it's inefficient and prone to weird warnings if you don't have an even-sized list. Worse yet, if you want to pass a list and a hash, or a scalar and a hash, or anything else, you can't disambiguate between them:
        sub foo { my %hash = @_; } # works fine foo(%hash); # uh oh foo('nameofhash', %hash); # not good at all foo(@names, %hash);
        If you can coerce all of your arguments into scalars, it's a lot easier to deal with them. (It's also more efficient, if you have a large list.) That's one reason people pass things by reference:
        # pass a reference to %hash, which is a scalar foo(\%hash); sub foo { my $hashref = shift; }
        You'll have to dereference it if you want to treat it like a hash, but that's usually a small price to pay. Since the hash reference is already a scalar, you can pass it to other subs as is:
        sub foo { my $hashref = shift; # add data bar($hashref); } sub bar { my $hashref = shift; # manipulate data as above }
        A reference to a hash is already a scalar (that's the point), so it's not necessary to take another reference to it. You'll just end up balding, with lots of curly braces. :)
        my %argHash = ( abcd => 'efgh', ijkl => 'mnop', ); &first(\%argHash); sub first { my $args = shift; print "$_ => $args->{$_}\n" foreach sort keys %$args; &second({%$args, qrst => 'uvwx'}); } sub second { my $args = shift; print "$_ => $args->{$_}\n" foreach sort keys %$args; }
        Or, if you don't want to use hashrefs, you can do
        my %argHash = ( abcd => 'efgh', ijkl => 'mnop', ); &first(\%argHash); sub first { my %args = @_; print "$_ => $args->{$_}\n" foreach sort keys %args; &second(%$args, qrst => 'uvwx'); } sub second { my %args = @_; print "$_ => $args{$_}\n" foreach sort keys %args; }
        Note how the two use different braces at different times. Either is just fine. The second is prone to more errors in coercing the array @_ into the hash %args, but, so long as you know exactly what's going into that hash, you should be fine. Try them out and see which you prefer.

        ------
        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.

Re: Re: Re: Understanding why strict prevents a use of local
by {NULE} (Hermit) on Oct 20, 2001 at 00:22 UTC
    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

Log In?
Username:
Password:

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

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

    No recent polls found