http://qs1969.pair.com?node_id=1023518


in reply to Is it safe to append to the array you are iterating over

G'day DrWhy,

In what sense does that code work? In what sense do you consider it to be safe?

I don't see any code requesting for warnings to be emitted. I don't see any sanity checks. I don't see any tests for ... well, anything. Perhaps worked safely means it finished before flames burst forth from the back of your computer :-)

What would happen if, at some later time, a fourth conditional push() was added:

push @arr, $some_var if $_ eq 'd';

If $some_var happens to evaluate to 'a', you're now stuck in an infinite loop.

There's all sorts of other scenarios that result in infinite loops, chewing up inordinate amounts of processor or memory resources, leaving the array in a state that has adverse consequences for subsequent processing and so on.

In general, this practice is not safe; moreover, it can easily be avoided.

-- Ken

Replies are listed 'Best First'.
Re^2: Is it safe to append to the array you are iterating over
by DrWhy (Chaplain) on Mar 14, 2013 at 18:57 UTC
    By the code working I expect that the for loops over the entire array contents including the elements added in the loop body. The expected output of this code is
    abcdef
    
    Which is in fact what I get when I run it. By safe I mean it doesn't crash or do something else unexpected when I run it. I added use strict and use warnings and the code still worked fine. No warnings emitted, no strictness violations. I'm not sure what kind of sanity checks you might add to this code. I suppose you could check at the end of the loop that the array had exactly the expected six elements in it.

    It is clear to me that this technique used incorrectly could lead to creation of an infinite loop, but that is just a programmer/algorithmic GIGO type issue.

    Yes, you can argue that it is unsafe because a user could accidentally write their algorithm in such a way that some data causes it too loop infinitely. But that's not the kind of safe I'm asking about. By safe I mean this. If I write a piece of code using this pattern and it works as I expected in this version of perl, is it likely to break unexpectedly when I run the same code on a different version of perl, because the fact of it working as expected depended on an implementation detail of the interpreter rather than a supported feature of the interpreter.

    Or to restate the original question. The following behavior works in Perl 5.10.0 (linux/multi threaded): a for loop using an array as the sole element of its loop list can loop over the entire array even if that array is extended inside the loop body -- so the definition of 'entire' changes as the loop is executed and the array gets longer. Is this behavior a supported feature of the language which can be relied upon to work generally across future versions of perl or is it an implementation detail subject to unexpected and undocumented change?

    --DrWhy

    "If God had meant for us to think for ourselves he would have given us brains. Oh, wait..."

      The problem is that even if the logic in the loop body doesn't cause an infinite loop; you are at the very least also iterating over all the additional elements that you push for no good reason. You've just pushed those values; you presumably don't want them to cause further pushes.

      Why do pointless extra work when it is so easily avoided?


      With the rise and rise of 'Social' network sites: 'Computers are making people easier to use everyday'
      Examine what is said, not who speaks -- Silence betokens consent -- Love the truth but pardon error.
      "Science is about questioning the status quo. Questioning authority".
      In the absence of evidence, opinion is indistinguishable from prejudice.
      /div
        I disagree with your 'for no good reason' part. In my use case, I have a very good reason to want this to happen. (I mean the real code I'm working on, not the baby example I used in the OP). I'm using it to traverse a tree of nodes and build a list (actually a hash) of data about the nodes.

        But as I said in another comment, I'm switching to using an implementation that uses a while loop instead that's clearly safer.

        --DrWhy

        "If God had meant for us to think for ourselves he would have given us brains. Oh, wait..."