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

Hi,
I used that code, which works fine for me:
$\ = $/; sub add{ my ($i, $j, $add) = @_; $_{value}[$i][$j] += $add; } while(<DATA>){ $tc ++; print "[$tc]"; ($n, $m) = split; for $i (1 .. $n){ $_ = <DATA>, chomp; for $j (1 .. $m){ $_{value}[$i][$j] = substr $_, $j - 1, 1; } } &add(2, 3, 5); for $i (1 .. $n){ print join " ", @{ $_{value}[$i] }; } } __DATA__ 3 3 011 111 111 6 7 1101011 0111111 1111101 1111111 1111110 0111111
OUTPUT:
[1] 0 1 1 1 1 6 1 1 1 [2] 1 1 0 1 0 1 1 0 1 6 1 1 1 1 1 1 1 1 1 0 1 1 1 1 1 1 1 1 1 1 1 1 1 1 0 0 1 1 1 1 1 1

... but later I wanted to collect all my matrixes, so I tried to replace this "$_{value}[$i]" with that "$_[$tc]{value}[$i]" (I inserted [$tc] in all such places). And now seems that my subroutine fails? The OUTPUT is:
[1] 0 1 1 1 1 1 1 1 1 [2] 1 1 0 1 0 1 1 0 1 1 1 1 1 1 1 1 1 1 1 0 1 1 1 1 1 1 1 1 1 1 1 1 1 1 0 0 1 1 1 1 1 1
Program:
$\ = $/; sub add{ my ($i, $j, $add) = @_; $_[$tc]{value}[$i][$j] += $add; } while(<DATA>){ $tc ++; print "[$tc]"; ($n, $m) = split; for $i (1 .. $n){ $_ = <DATA>, chomp; for $j (1 .. $m){ $_[$tc]{value}[$i][$j] = substr $_, $j - 1, 1; } } &add(2, 3, 5); for $i (1 .. $n){ print join " ", @{ $_[$tc]{value}[$i] }; } } __DATA__ 3 3 011 111 111 6 7 1101011 0111111 1111101 1111111 1111110 0111111
I can't understand why it fails.

Replies are listed 'Best First'.
Re: can't find mistake. lost in references
by hdb (Monsignor) on Mar 14, 2015 at 17:24 UTC

    In your first version you use %_ to store data, which is a strange choice of variable. In the second version you use @_ to store your data which is very strange and - as you found out - has funny side effects. I have not really looked at your code but using $mat[$tc] instead of $_[$tc] everywhere should solve your problem.

    UPDATE: In your subroutine

    sub add{ my ($i, $j, $add) = @_; $_[$tc]{value}[$i][$j] += $add; }

    you are even referring to two different @_ arrays explicitly. The one that passes the parameters into the subroutine and the global one that you use to store your data.

      you are even referring to two different @_ arrays explicitly. The one that passes the parameters into the subroutine and the global one that you use to store your data.

      :) There is only one @_ and it is "super global" that is anytime you write @_ its always @_ (its always @main::_ ) regardless of package

      Symbol isn't exactly authoritative but it does show this

      $ perl -MSymbol=qualify -le " print qualify($_,q/Fooo/) for qw/ ARGV S +TDOUT STDERR _ AHOY / main::ARGV main::STDOUT main::STDERR main::_ Fooo::AHOY

      pervar says: Perl identifiers that begin with digits, control characters, or punctuation characters are exempt from the effects of the package declaration and are always forced to be in package main ; they are also exempt from strict 'vars' errors. A few other names are also exempt in these ways: ENV STDIN INC STDOUT ARGV STDERR ARGVOUT SIG

        Thanks for the clarification! I should have said something like: referring to @_ as if there were two of them...

        He'd have the same problem even if @_ wasn't a "super global". The actual problem is that sub calls localize @_ as part of placing the arguments in it.

        PS - There can be more than one @_ in every package. It's just that unqualified @_ always refers to @::_. You can access package Foo's @_ using @Foo::_.

      Ok, thank you! Now it is clear. I changed location of "[$tc]" to "$_{value}[$tc][$i][$j]", now it works.

        Another alternative would be to use a regular variable instead of $_. Using a variable that depends on context sounds like a great way to ensure confusion.

        replace $_[$tc]{value}[$i][$j] with $matrix[$tc]{value}[$i][$j]

        Updated to remove liability

        Dum Spiro Spero