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

I saw something similar in another post, and am surprised and perplexed that I can't use an array element as the for loop iterator. See the code snippet below. Is this a bug, anomaly, idiosyncracy, or by design?
#! user/bin/perl use warnings; use strict; my @x = ( [1,1], [2,2], [3,3] ); my @y; sub do_something {} # this is what I want, but--- gets "syntax error ... near "$y[" # foreach $y[0] (@x) { <=== syntax error on this line # foreach $y[1] (@x) { # do_something(@y); # } # } # so, I use this method instead foreach (@x) { $y[0] = $_; foreach (@x) { $y[1] = $_; do_something(@y); } }

Replies are listed 'Best First'.
Re: array element as foreach iterator
by ikegami (Patriarch) on Jan 27, 2005 at 17:00 UTC

    It's consistent with the documentation, which says a VAR is expected (with an optional my). $y[0] is an expression, not a variable. I suppose it could be considered a limitation, but not a bug.

    The following can be used. If you want to next an arbitrary number of loops, check out Algorithm::Loops.

    foreach $y0 (@x) { foreach $y1 (@x) { do_something($y0, $y1); } }
      It's consistent with the documentation, which says a VAR is expected (with an optional my).

      It should be pointed out that if the variable is already declared lexical in an enclosing scope then the my is assumed. i.e. it is not the previously declared lexical that is used but a different one.

      IMNSHO perl should throw a warning when it infers an implicit my.

      OK, that explains why. I must use simple scalar variables (or the default $_) as a for/foreach iterator. Thanks.
Re: array element as foreach iterator
by Tanktalus (Canon) on Jan 27, 2005 at 16:55 UTC

    I have to admit - I've never thought about doing this ... but I can see how that would be some really nice-tasting syntactic sugar.... I would normally look at it this way:

    #! user/bin/perl use warnings; use strict; my @x = ( [1,1], [2,2], [3,3] ); sub do_something {} # so, I use this method instead foreach my $a1 (@x) { foreach my $a2 (@x) { do_something($a1, $a2); } }

    But maybe that's just me thinking "inside the box" again.

      Yes, that too was my first thought. But, I actually had 10 nested foreach loops, and the programmer inside said "sounds like an array", so I tried to use elements of an array as the iterators. As always, TMTOWTDI.
        I actually had 10 nested foreach loops, and the programmer inside said "sounds like an array"

        The programmer inside me says "sounds like recursion".

Re: array element as foreach iterator
by davido (Cardinal) on Jan 27, 2005 at 16:52 UTC

    Yes, you can't do that. Why would you want to? Ultimately what are you trying to accomplish? There's probably a better way.


    Dave

Re: array element as foreach iterator
by fglock (Vicar) on Jan 27, 2005 at 20:06 UTC
    use strict; my @end = ( 3, 3, 3 ); my @start = ( 0, 0, 0 ); my @index = @start; LOOP: while (1) { print "this is loop position [ @index ] \n"; for my $q ( reverse 0 .. $#start ) { $index[$q]++; last unless $index[$q] >= $end[$q]; last LOOP unless $q; $index[$q] = $start[$q]; } } print "done \n";
    this is loop position [ 0 0 0 ] this is loop position [ 0 0 1 ] this is loop position [ 0 0 2 ] this is loop position [ 0 1 0 ] this is loop position [ 0 1 1 ] ........................... this is loop position [ 2 1 0 ] this is loop position [ 2 1 1 ] this is loop position [ 2 1 2 ] this is loop position [ 2 2 0 ] this is loop position [ 2 2 1 ] this is loop position [ 2 2 2 ] done
Re: array element as foreach iterator
by ambrus (Abbot) on Jan 28, 2005 at 09:34 UTC

    You can have it like this, with some syntactical constraints:

    sub forache { for my $v (1..@_-2) { $_[0] = $_[$v]; &{$_[-1]}(); } } my $k; forache $k, ("greetings, ", "all\n"), sub{ print $k; }; my @a = ("hello, ", "<name>", "\n"); forache $a[1], ("james", "andy", +"bob", "david"), sub { print @a; };
Re: array element as foreach iterator
by ambrus (Abbot) on Jan 28, 2005 at 09:15 UTC

    I think it's by design. Foreach aliases the variable. This limitation is so that you can't easily create arrays with aliased elements, or people would end up with modifying an array element and wondering why an other array has changed. People would keep asking why that happens.

    Update: Let me meake this clearer. You can have array elements aliased to each other like this.

    @y = ("this", "that"); *x = &{sub {\@_}}(@y[reverse 0..@y-1], "your"); + print "@x\n"; # ==> that this your $y[0] = "great"; # I change @y print "@x\n"; # ==> that great your # hey, why did @x change, I didn't do anything with @x!
    Clearly, no-one would actually write code like this (except in How's your Perl? (II)). If, however, foreach allowed us to create such strange arrays, that could cause strange bugs.