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

I have a hash array that I want to use to hold useful information for debugging purposes for a large Perl program.

The problem is that while I can add an entry to a hash in a subroutine, when the program flow returns to main(), the entry in the hash is no longer there, due to problems with the scope.

The code is as this:
our %debug = (); $debug{'level'} = 1; $debug{'stack'}[0] = "main()"; $rv = MyModule::testStack(\%debug); my @t = $debug{'stack'}; my $CountMain = scalar (@t); print "$CountMain \n"; # This prints 1 #Now there is another subroutine defined in another module: sub testStack { my $ptr = $_[0]; my %h = %$ptr; my @a = $h{'stack'}; push (@a, "testStack()"); my $count = scalar (@a); print "$count \n"; # This prints 2 return 1; }


I am passing the hash array "debug" to testStack() by reference. Yet, when I want to add an element to the array debug{'stack'} in testStack(), it is not added to the debug of main()'s scope.

How do I get around this problem? I would like to refer to $debug{'stack'} as an array so I can use push/pop functions.

Replies are listed 'Best First'.
Re: How do I add entries to a hash array in a different scope?
by jettero (Monsignor) on Oct 10, 2009 at 11:41 UTC
    This isn't really a scope question. The problem is: you can't store an array in a hash. You can store an arrayref though.
    use strict; # important use warnings; # important my %debug; # you rarely want our (or local) test_push(\%debug); print "hey, it works: $_\n" for @{ $debug{stack} # this probably contains our arrayref || [] # but if it doesn't, don't error out please }; sub test_push { # avoid camel case (imo) my ($debug) = @_; push @{ $debug->{stack} }, "lol"; # avoid unnecessary derefs # or my $ar = $debug->{stack}; push @$ar, "lol2"; return; }

    Check out docs like perlreftut, perldata, perllol for further information.

    -Paul

Re: How do I add entries to a hash array in a different scope?
by zwon (Abbot) on Oct 10, 2009 at 11:43 UTC

    You didn't show how are you adding element into $debug{stack} in testStack, but if $ptr contains reference to %debug, you can do it as follows:

    push @{$ptr->{stack}}, $new_elem; $ptr->{stack}[7] = $new_value;

    Also see References quick reference.

Re: How do I add entries to a hash array in a different scope?
by NetWallah (Canon) on Oct 10, 2009 at 15:36 UTC
    Your statement
    my %h = %$ptr;
    makes a (shallow) COPY of the hash, via the hash-ref.

    Then

    my @a = $h{'stack'};
    make a COPY of the array-ref into the zero'th element of @a (probably not what you intended).

    zwon(++)'s solution works directly off the references to the original objects.

    If you want to use the syntax you are attempting, you need to make symbolic references, instead of copies:

    local *h=$ptr; # %h now is synonymous with %debug local *a=\$h{stack}; # @a is another name for the anon array @{ $h{ +stack} } # Now, a 'push' into @a will change %debug
    (Untested). See 'Typeglobs and Filehandles' in 'Perldata'.

    You will need to tweak 'use strict', to enable typeglobs.

         Potentia vobiscum ! (Si hoc legere scis nimium eruditionis habes)