Page 1 of 1

How to avoid infinite loops due to nested ForEach?

Posted: Fri May 02, 2025 10:52 am
by Joubarbe
I often find myself - in complex code - calling a function in a ForEach that also has a ForEach on the same list.

Code: Select all

Global NewList foo()

For i = 1 To 10
  AddElement(foo()) : foo() = i
Next i

Procedure FindFoo(int)
  ForEach foo()
    If foo() = int
      ProcedureReturn @foo()
    EndIf
  Next
EndProcedure

ForEach foo()
  Debug foo()
  FindFoo(5)
Next
Infinite loop.

I'm wondering if you guys had some safety net to avoid that. I'm tempted to Push/PopListPosition() every time after ForEach and before Next, with a custom macro... or just be careful :D (but infinite loops can be tricky to debug)

Re: How to avoid infinite loops due to nested ForEach?

Posted: Fri May 02, 2025 11:07 am
by RASHAD
Maybe
Use Break to get out :)

Code: Select all

ForEach foo()
  x+1
  Debug foo()
  FindFoo(5)
  If x >= 100
    Break
  EndIf
Next

Re: How to avoid infinite loops due to nested ForEach?

Posted: Fri May 02, 2025 11:49 am
by Joubarbe
But then you don't do what you're supposed to do. You never get past foo(5).

Code: Select all

ForEach foo() : PushListPosition(foo())
  Debug foo()
  FindFoo(5)
PopListPosition(foo()) : Next
Kinda neat, no? :?

Or I would have to keep track of list index, like if I was browsing an array. Hmm...

Re: How to avoid infinite loops due to nested ForEach?

Posted: Fri May 02, 2025 11:52 am
by Axolotl
Hi,

maybe you can make the loop inside the procedure a little more secure with the use of:

Code: Select all

  PushListPosition(List())
  ; ... do your stuff....  
  PopListPosition(List())
Adapted to you example:

Code: Select all

Procedure FindFoo(int)
  Protected result 

  PushListPosition(foo())
  ForEach foo()
    If foo() = int
      ; ProcedureReturn @foo()
      result = @foo() 
      break 
    EndIf
  Next
  PopListPosition(foo()) 
  ProcedureReturn result 
EndProcedure
Example From Help :

Code: Select all

  ; A simple duplicate elimination using a nested iteration
  ;
  ForEach Numbers()
    Value = Numbers()
    PushListPosition(Numbers())
    While NextElement(Numbers())
      If Numbers() = Value 
        DeleteElement(Numbers())
      EndIf
    Wend
    PopListPosition(Numbers())
  Next
Ups: Too late....

Re: How to avoid infinite loops due to nested ForEach?

Posted: Fri May 02, 2025 12:03 pm
by Axolotl
I dont know what this is for, but the following shows the differences with my FindFoo() to your code above:

Code: Select all

Global *No5 

ForEach foo()
  Debug foo()
  *No5 = FindFoo(5) 
Next

Debug ""
Debug foo() 
Debug PeekI(*No5) 

ChangeCurrentElement(foo(), *No5) 
Debug foo() 

Re: How to avoid infinite loops due to nested ForEach?

Posted: Fri May 02, 2025 12:14 pm
by mk-soft
This query makes no sense to me ...

Re: How to avoid infinite loops due to nested ForEach?

Posted: Fri May 02, 2025 1:32 pm
by Fred
If a procedure modify a global list, and can be used anywhere you should protect the iteration with push/PopListPosition().

Re: How to avoid infinite loops due to nested ForEach?

Posted: Fri May 02, 2025 2:56 pm
by skywalk
I use the suggested help flow:

Code: Select all

ForEach ll()
  ;..some code
  PushListPosition(ll())
  While NextElement(ll())
    ;..some code
  Wend
  PopListPosition(ll())
Next
Be careful when calling this type of code from a thread.

Re: How to avoid infinite loops due to nested ForEach?

Posted: Fri May 02, 2025 3:21 pm
by Joubarbe
Thanks all :)