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

Hi all. Here's the problem I have: in my main application I declare a hash called returnVals. I call a subroutine &createExcelChart that passes the hash in as *returnVals. In the module (I've called the parameter returnVals and then returnValues to make it different than the calling program) I set the hash value of ExtendedName to a value and shortly after return to the calling program. When I print the value on the main (calling) program I don't get anything and it has no keys at that point. At the end of the module's subroutine I print the value and key fine. Can anyone suggest what I can do to solve this problem (which looks like a scope problem)? I have 2 other hashes used pretty much the same way (i.e. declared, passed to the sub, assigned, and returned) and they "seem" to work fine except those other 2 hashes are declared before calling the subroutine and their values remain unchanged in the sub. The values from these 2 hashes are accessed fine within the sub as well.

Replies are listed 'Best First'.
Re: Scope of a Hash
by ikegami (Patriarch) on Dec 15, 2005 at 16:05 UTC

    Why don't you post your code instead of describing it? Be sure to twiddle it down to a minimum size before post it, and please wrap your code <c>...</c> tags.

    The fact that you're using globs is... very odd. Try using a reference to the hash, or the hash itself if you want to make a copy of it.

Re: Scope of a Hash
by secret (Beadle) on Dec 15, 2005 at 16:06 UTC

    I call a subroutine &createExcelChart that passes the hash in as *returnVals.

    AAaaah !!! Why do you do this ??
    Don't use typeglobs to pass variables around !
    It's illegal ! It's punished by The Law (tm) ! It will not work with use strict !

    If you want to pass a hash to a function you should use a reference to the hash, i.e :

    my %hash = ( 'some' => 'things' ) ; callFunction( \%hash ) ;
    In the function you can for example dereference the hash :
    sub callFunction { my $refhash = shift ; my %hash = %$refhash ; ... }

      It will not work with use strict!

      It won't? Coulda fooled me.

      use strict; use warnings; sub foo { our $bar; $bar = "Hi"; return *bar; } my $foo = foo(); print $$foo, "\n"; __OUTPUT__ Hi

      Not that I disagree with the rest of your post, though. This type of thing is odd, but it's not disallowed by strict by any means.

Re: Scope of a Hash
by Anonymous Monk on Dec 15, 2005 at 16:19 UTC
    Typeglobs... I work for a small company whereby this is how the code I've used was done. Since the apps aren't really complex in nature I keep going with it and being that I "learned" how to program in perl from these I had stuck with it. Now I'm trying to find more efficient ways of doing things in the apps since we are getting involved with more complex applications. So basically "escaping" (sort of I know) grabs the memory location and $$, %$, or @$ will grab the appropriate reference to this location? I had tried using this just prior to posting this actually but it didnt seem to work. I'll try again making sure all the "i"s are dotted. Thanks again.
      I'm still not getting exactly what I wanted here are some lines of code that I am using. I've posted the lines related the hash that I'm having trouble with). The code is not as efficient as you'll probably think but I'm working on it. On the main application:
      %returnVals = (); %X_Axis = (); %Y_Axis = (); $ExcelLink = &swOpenExcel("FILE", $lAppName, $wbFullDirectory, $wbChar +tDirectory, $wbExcelName, $wbExcelData, $dataCol, $strtRow, $labelCol +, $endRow, $typeGraph, $ChartName, $lChartTitle, 'JPG', $lLegendKey, +$lData_Labels, $fields{$q->param(X_Col)}, $fields{$q->param(Y_Col)}, +\%returnVals, \%X_Axis, \%Y_Axis);
      In the module:
      ($typeData, $AppName, $wbFullDirectory, $wbChartDirectory, $wbExcelNam +e, $wbExcelData, $dataCol, $strtRow, $labelCol, $endRow, $typeGraph, +$ChartName, $ChartTitle, $filter, $LegendKey, $LegendType, $rVals, $X +, $Y) = @_; my %X_Axis = %$X; my %Y_Axis = %$Y; my %returnValues = %$rVals; $returnValues{"ExcelLink"} = "/Web$AppName/Charts/" . $wbExcelName . " +_" . $extension . "\.xls";
        my %returnValues=%$rVals; does not setup an alias, as you seem to assume, but copies the $rVals hash. If you change the copy afterward with $returnValue{"ExcelLink"}=... the original doesn't follow. Either copy back with %$rVals=%returnValues; or change the original instead with $rVals->{"ExcelLink"}=...
        I'm still not getting exactly what I wanted here

        If you don't get it, then how do you expect us to? ;-)

        Jokes apart, at first sight your code seems more complex then it may actually be. Can you consider refactoring it in a more "efficient" (human-wise!) way? Said this, an advice that pairs well with the good "do not use typeglobs for this" one is: do not use the &-form of sub call: it is not necessary and obsolete in modern perls. It may be safe enough, but it doesn't do what you want and it's still there for another purpose: see perldoc perlsub.

        $ExcelLink = &swOpenExcel( .. 21 variables .. ); sub swOpenExcel { ## I assume ( ... 19 variables ... ) = @_;

        That is going to cause you some severe problems.

        I would also recomend you rename $rVals, $X, and $Y to something like $rVals_ref, $X_ref, and $Y_ref just to remind you that you are using refs into the future.