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

Hello Monks It's been a long time since I perl'ed! I have a program I wrote a few years back and I did all the bad things, global variables, variables with no initialization etc. (I was just learning at the time) So I have decided to re-write it, remove all global vars and make sure that use warnings,strict and diagnostics are happy. If there is more I should do to make perl happy, I am all ears. To my real question. In my 'main' program I have made some local hash tables that i am using to store and control the program and it's data. The thing that beat me up for an hour or two was 'scope' I believe I have a decent handle on it now, but am still struggling a little with implementation. Here's an example snippet.
# call the sub with a local hash play_around(\%toys); sub play_around { my %t = %{$_[0]}; # I found this the only way to get the has in properly, # otherwise it came in scalar, and mixing and matching # hash and scalars made me choose to load this way, if # it's wrong, please correct me. $t{'leggo'} = "yes"; # this only lasts locally in this sub $_[0]{'leggo'} = "yes"; # this will modify the actual %toys which is what I want. # But this is darned ugly! and with a number of # hashes / scalars it's a pain. Is there not a better # way, or have I crossed the line into being a # bad practice perl programmer? }
Thank you in advance for any insight to my non-grasping of pointer/var handling in perl. I'm used to C and don't have too much trouble there!

Replies are listed 'Best First'.
Re: passing of variables
by wind (Priest) on May 06, 2011 at 17:37 UTC

    Yes, just access the hash by reference

    sub play_around { my $hashref = shift; # This will effect the outside hash $hashref->{leggo} = "yes"; ... }

    That's what you're doing when you use ${$_[0]}{leggo}.

      Sheash, it must have been far too late last night at 1am. This worked nicely in my test, Thanks to all for the help. I could have sworn I tried something like this, but obviously not quite this ;-) Thank you Wind! (and the other posters!)
Re: passing of variables
by ikegami (Patriarch) on May 06, 2011 at 17:46 UTC

    this only lasts locally in this sub

    # Creates a hash %t that has the same contents as %toys my %t = %{$_[0]}; # Modifies %t (which is unrelated to %toys) $t{'leggo'} = "yes";

    [$_[0]{'leggo'} = "yes";] is darned ugly!

    Since you're not changing the reference itself (only that to which it refers), you can copy the reference into a more suitably named variable.

    my ($toys) = @_; $toys->{'leggo'} = 1;

    Note that 1 and 0 (or undef) are usually used for boolean. It's not that using "yes" is problematic, it's that "no" isn't false. Formatting outputs (e.g. converting to "yes" and "no") should be done on output.

      Agreed on the last comment, I choose my example a little poorly I suppose :-) Thanks for the help to monks!!
Re: passing of variables
by tchrist (Pilgrim) on May 06, 2011 at 18:07 UTC
    Here’s how to do what you want to do:
    use strict; use warnings; use Data::Dump; { my %toys = ( frisbee => 5 ); dd \%toys; play_around(\%toys); dd \%toys; } sub play_around { die "expected one arg" unless @_ == 1; die "expected hash arg" unless ref($_[0]) eq "HASH"; our %t; local *t = $_[0]; $t{leggo} = "yes"; }
    When run, that prints out:
    { frisbee => 5 } { frisbee => 5, leggo => "yes" }
    See? Nice and easy!
      Interesting, this method actually seems easier to read too, I especially like the die's that you have included, I try to error check, but sometimes in perl am not sure how, so thank you again for this wonderful example.
        I think that's a bit "advanced" or "tricky", and not something you should imitate just now. Get used to dealing with $$name{key} and $name->{key} syntax, as that is present everywhere in modern Perl.

        Using a localized package variable instead of a true lexical variable will lose the benefit of lexical variables: if the function calls another function that uses the package variable, it will see the current local-ized use of it.

        The Perl debugger will let you see exactly what is going on. I almost always end up using it when dealing with nested data structures or hashes.
Re: passing of variables
by jwkrahn (Abbot) on May 06, 2011 at 17:40 UTC
    # call the sub with a local hash play_around( \%toys ); sub play_around { my ( $t ) = @_; $t->{ leggo } = 'yes'; # this will modify the actual %toys which is what I want. }