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

well,

i was messing around with implementing some security into my program and i noticed some strange thing in one of my foreach loops

foreach (@array){ do something $self->_call($_); do something else }
if the number of arguments were higher than 50 in @array the foreach skipped all the variables over it. if the $_ argument was very complex then the limit was 20 arguments. so my question now is: is it possible that foreach will loop not waiting for the object (_call()) to finish and just go on. because if it is, then i have a serious problem. my program through time build up to huge number of lines and huge number of number of foreach loops.

if this is the case then please help me with some quick fix.

thnx

PS

it is interesting that i always stumble over some basic stuff, did anyone noticed the same problem (stumbling over basics while at the same time writing solutions to a really hardcore stuff)?

UPDATE:

ok what happens is this:

sub _do { my ($self,%arg) = @_; unless(%arg){ # some stuff (~200 lines) foreach my $choice (@array_choices){ # + log update my @choice_array = split(",",$print_hash{$choice}); my $pick; ($choice_array[0] eq 'correct') ? ($pick = "$choice_array[1]-$ +choice_array[2]") : ($pick = $choice_array[1]); # pick for correctio +n $self->_do($choice_array[0] => $pick); + # repete undo precedure with defined values ($choice_array[0] eq 'correct') ? (delete $class_log{do}[$hash +_order{$choice_array[0]}]) : (delete $class_log{do}[$hash_order{$prin +t_hash{$choice}}]); # delete do choice push(@return_log,"_do($choice_array[0] => $choice_array[1]);") + unless (ref $pick eq 'ARRAY'); # data for physh push(@return_log,"_do($choice_array[0] => \[$choice_array[1],$ +choice_array[2]\]);") if (ref $pick eq 'ARRAY');# data for physh } } else{ # brute _do } }
so what happens is ido something and then use the loop to automatically delete the data from the array instead of writing another loop to do that

so the answer to grizzley's second question is yes my mistake both answers are no (at least it seams for now, let me check again)

also the sub uses some ~100 other objects in the first part is the sub (it is a final wrapper) so showing you the whole script won't do any good

UPDATE2:

the loop and objects called within the loop are "redo,last" free, no such calls are made

Replies are listed 'Best First'.
Re: foreach loop - could it beeeeee!!
by ELISHEVA (Prior) on Oct 09, 2009 at 11:21 UTC

    What exactly are you doing in "doSomething", "doSomething", and "_call"? Can you show us some working code that illustrates the problem, i.e. code we can download and run (without having to install the world as dependencies)? If this is happening at all it certainly isn't happening for every possible "doSomething" or "doSomethingElse" or "_call". Perl regularly handles very large arrays in for loops. For example, the following code shows no evidence of wierd behavior for arrays with 1000+ elements.

    Absent any other information, I would guess one of two things:

    • more likely: either "doSomething" or "doSomethingElse" is messing with @array in some way that you have overlooked. (it happens to us all).
    • less likely: that you might be running into problems by passing $_. There is a lot of magic associated with that variable. I can't see right off why it would cause a problem, but if I were debugging this in my own code my first step would be to replace $self->_call($_) with my $x=$_; $self->_call($x);

    Update: In response to OP's update, I have added code to illustrate why deleting elements from a loop you are currently iterating through is a bad idea (Perl will let you do it, but the foreach loop isn't expecting it).

    Update2: (3:15 IST) Added an explanation of why deleting elements from arrays can cause loops to process elements in unexpected ways - see both immediately above and in code sample.

    Best, beth

Re: foreach loop - could it beeeeee!!
by grizzley (Chaplain) on Oct 09, 2009 at 10:47 UTC
    Its guessing without seeing original code. Some thoughts:
    • Do you use inside loop or in your calls 'next', 'redo' or other control statements?
    • Do you add/remove some elements from @array inside loop?

    It would be good to see those nested loops, we would definitely enjoy optimising them.

Re: foreach loop - could it beeeeee!!
by ikegami (Patriarch) on Oct 09, 2009 at 14:56 UTC
    btw,
    my $pick; ($choice_array[0] eq 'correct') ? ($pick = aaa) : ($pick = bbb);
    should be
    my $pick = $choice_array[0] eq 'correct' ? aaa : bbb;
      Surely ‘should’ (instead of ‘could’) is a bit strong? “Your code isn't as brief as it could be” is quite different from “Your code must be changed”; and, especially for folks like me who can never remember precedence, it's easy on a quick read to bracket as
      (my $pick = $choice_array[0]) eq ('correct' ? 'aaa' : 'bbb')
      , which makes the whole very confusing. There's not even any potential for repeated side effects with the original code—it's just a tiny bit of repeated typing.
        If you're going to start arguments about "readability for newbies", then I'll chip in and simply state that a "?:" syntax construct should not be used for statements (in void context), but only for expressions. For statements you should be using if/else instead.
        my $pick; if($choice_array[0]) eq 'correct') { $pick = 'aaa'; } else { pick = 'b +bb'; }

        All IMHO, of course.

        Finally, I must say that I think that all this "readability for newbies" is all a pile of nonsense. Just make it readable for yourself.

        Surely ‘should’ (instead of ‘could’) is a bit strong?

        I don't think so. Anything but the trivial use of the conditional operator is usually unreadable. The OP's code is definitely unreadable. Part of the reason his code is unreadable is due to his non-standard and verbose use of the conditional operator.

        it's easy on a quick read to bracket a

        I usually add parens around the conditional operator for similar reasons:

        my $pick = ( $choice_array[0] eq 'correct' ? aaa : bbb );
        my $pick = ( $choice_array[0] eq 'correct' ? aaaaaaaaaaaaaaaaaaaaaaaaaaa : bbbbbbbbbbbbbbbbbbbbbbbbbbb );
Re: foreach loop - could it beeeeee!!
by JavaFan (Canon) on Oct 09, 2009 at 11:44 UTC
    Are you sure you don't have a 'last' outside of a loop in _call, or one of the subs it calls?