[Date Prev][Date Next][Thread Prev][Thread Next] [Search] [Date Index] [Thread Index]

Re: [MacPerl] foreach and referenced array



On Tue, 12 Mar 1996, Alain Fontaine wrote:

> $numb = 20;
> 
> @stack = ([3,1,1,[]]);
> &printstack;
> $stack[0][3][2] += 5;
> &printstack;
> for ($i=0;$i<=$#{$stack[0][3]};$i++) {
>   $stack[0][3][$i] *= $numb;
> }
> &printstack;
> 
> @stack = ([3,1,1,[]]);
> &printstack;
> $stack[0][3][2] += 5;
> &printstack;
> foreach $x (@{$stack[0][3]}) {
>   $x *= $numb;
> }
> &printstack;
> 
> sub printstack {
>   foreach $x (@stack) {
>     print "\[$x->[0], $x->[1], $x->[2], \[",join(', ',@{$x->[3]}),"\]\]\n";
>   }
> }
> I would have expected the same result from the two versions. But running
> it, I get:
> [3, 1, 1, []]
> [3, 1, 1, [, , 5]]
> [3, 1, 1, [0, 0, 100]]
> [3, 1, 1, []]
> [3, 1, 1, [, , 5]]
> # Modification of a read-only value attempted.
> File 'PB540 Alain:Documents:BH:Stat:Unités:Test'; Line 17
> 
> I know that $x can only be used on the left of an assigment if the
> second argument of the foreach is an array, and not an expression
> returning an array value. Here, I have an array accessed by reference.
> Any comments from the confirmed Perl gurus ? Thanks.

I think the problem is that the first two elements of the inside array are 
undefined.  If there is already a value in the array slot, the foreach 
provides $x that is an lvalue--your not changing where the value is 
stored, just the value.  However, if the array slot is undefined, it will 
try to allocate space for the value, which would require updating 
that slot's pointer to point to the newly allocated space.  However, the 
foreach is only working with a local copy of the 'pointer' and thus 
cannot change it (it's 'read-only' as it complained) to go from undefined 
to defined.

I don't know if that made sense, but the way to solve your problem is 
either:

1) make sure each item in the array is already defined with some value.

or 2) only do the multiplication if the $x is defined.

#2 seems to me much better and can be accomplished with a simple addition:

foreach $x (@{$stack[0][3]}) {
  $x *= $numb if defined($x);
              ^^^^^^^^^^^^^^
}

Now, that leaves the undefined slots undefined, but they will still be 
interpreted as the value '0' in a numeric context.

Hope that helps.

John Peterson -- University Networking Services -- Brigham Young University
Internet: John_Peterson@byu.edu                       Phone: (801) 378-5007