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

I have a function that takes a reference to hash as a parameter. This has has one element that's a reference to (multidimensional) array. Now, I tamper a lot with that array and the form $$hash{arraykey}[$i][$j] notation is a bit tiresome compares to $array[$i][$j], not to mention that other uses such as @{$$hash{arraykey}} can get pretty confusion. So, I figured, why not alias them? We have this local() function here just for that (amongst other things...), right? After some pretty confusing warnings, here's a testbed I used to track down the problem. It's not pruned enough to get to the core, but close enough, I suppose.
%hap=( 'foo' => "hip", 'bar' => [ 2, "blah", ], ); hum(\%hap); print "$hap{foo} $hap{bar}[0] $hap{bar}[1]\n"; sub hum { local *hash=$_[0]; local *array=$hash{bar}; print "$hash{foo} $array[0] $array[1] / @array\n"; # print "$hash{foo} @array\n"; $hash{foo}="gaa"; $array[1]=5; }

Now, see the print lines in sub hum. On my perl 5.6.0, the form I just pasted works fine, whereas commenting the first print out and uncommenting the second gives

In string, @array now must be written as \@array at ./test2.pl line 17, near "} @array"

Now, the only difference is that I use values inside that @array before using the @array itself. Did I get something about local() wrong here, or is that a genuine bug? And do you have any comments on how I should go on with aliasing @{$$_[0]{bar}} to @array ?

Replies are listed 'Best First'.
Re: local() peculiarities
by merlyn (Sage) on Jan 22, 2001 at 07:09 UTC
    local is primarily a run-time operation, but the warning you're getting is a compile time warning. And yes, there's been no specific use of @array down to the interpolation, so the compiler is rightly whining. I think you can add this to get things clean again:
    use vars qw(@array);
    Because that promises that there will be a symbol named @array at runtime, and therefore I can call it without a package.

    -- Randal L. Schwartz, Perl hacker

      Nice. Works. How do I cancel it? "no vars qw(blabla)" or even "no vars" doesn't do it. See:

      @jea=([1,"one"],[2,"two"],[3,"three"],); huu(\@jea); sub huu { my $i; for $i (0 .. $#{$_[0]}) { if ($_[0][$i]) { use vars (@bla); local *bla=$_[0][$i]; print "$i: @bla\n"; } print "@bla\n"; } }

      As you can see, the later reference to "@bla" is still affected by "use vars" in above block; it doesn't give the warning/error it should. I thought the pragma should expire at the end of block (some doc implied that), but no...

      -Kaatunut

        I thought that was weird too, so I looked it up. It turns out that, unlike most pragmas, vars is not block scoped.

        Here's the snippet:

        Unlike pragmas that affect the $^H hints variable, the use vars and use subs declarations are not BLOCK-scoped. They are thus effective for the entire file in which they appear. You may not rescind such declarations with no vars or no subs.
Re: local() peculiarities
by japhy (Canon) on Jan 22, 2001 at 08:43 UTC
    Recent perls have a feature (I'm not entirely sure why) that if @foo is seen in an interpolated string before any element of @foo (or the entire array itself) is used in an expression, you'll get barked at. Using the symbol *foo is not good enough, but using subscripts like $foo[0] is.

    japhy -- Perl and Regex Hacker
      I was going to try to explain the reason for this feature, but then I thought, I bet it's in the documentation for the error message.

      `perldoc perldiag`

      In string, @%s now must be written as \@%s (F) It used to be that Perl would try to guess whether you wanted an array interpolated or a literal @. It did this when the string was first used at runtime. Now strings are parsed at compile time, and ambiguous instances of @ must be disambiguated, either by prepending a backslash to indicate a literal, or by declaring (or using) the array within the program before the string (lexically). (Someday it will simply assume that an unbackslashed @ interpolates an array.)
      So, the reason for this error message is to flag a change in the implementation that will be incompatible with earlier versions of Perl.