dcsimg
Results 1 to 21 of 21

Thread: [RESOLVED] Exiting a Nested For/Next Loop

  1. #1

    Thread Starter
    Addicted Member
    Join Date
    Nov 2018
    Posts
    220

    Resolved [RESOLVED] Exiting a Nested For/Next Loop

    Hello,

    What is the proper way to exit a nested For/Next loop.

    I have code in Command1_Click below that works with a GoTo statement.

    I want to get rid of the GoTo, so I re-coded in Command2_Click

    My use of j = 10 seems like a kludge to me,
    and I was wondering if there is a another (more accepted) way to do this?

    Code:
    Private Sub Command1_Click()
        
        For i = 1 To 10
            For j = 1 To 10
                For k = 1 To 10
                    If k = 3 Then GoTo 100
                Next k
            Next j
    100:
        MsgBox "@ 100 when i = " & i
        
        Next i
        
    End Sub
    Code:
    Private Sub Command2_Click()
        
        For i = 1 To 10
            For j = 1 To 10
                For k = 1 To 10
                    'If k = 3 Then GoTo 100
                    If k = 3 Then
                        MsgBox "@ 100 when i = " & i
                        j = 10
                        Exit For
                    End If
                Next k
            Next j
    100:
        'MsgBox "@ 100 when i = " & i
        
        Next i
        
    End Sub

  2. #2
    PowerPoster Zvoni's Avatar
    Join Date
    Sep 2012
    Location
    To the moon and then left
    Posts
    2,133

    Re: Exiting a Nested For/Next Loop

    So you actually want to jump two "For"-Levels out.
    It boils down to the age old "Flamewar" about the missing "Continue"-Statemtn which has been discussed to death here in the forum
    In case of your sample:
    Code:
    Private Sub Command2_Click()
        
        For i = 1 To 10
            For j = 1 To 10
                For k = 1 To 10
                    'If k = 3 Then GoTo 100
                    If k = 3 Then
                        MsgBox "@ 100 when i = " & i         
                        'Don't manipulate a For-Variable inside the loop!          
                        Exit For
                    End If
                Next k
            If k=3 then Exit For
            Next j
        'MsgBox "@ 100 when i = " & i
        
        Next i
        
    End Sub
    One System to rule them all, One IDE to find them,
    One Code to bring them all, and to the Framework bind them,
    in the Land of Redmond, where the Windows lie
    ---------------------------------------------------------------------------------
    People call me crazy because i'm jumping out of perfectly fine airplanes.
    ---------------------------------------------------------------------------------
    For health reasons i try to avoid reading unformatted Code

  3. #3
    Fanatic Member
    Join Date
    Dec 2014
    Posts
    969

    Re: Exiting a Nested For/Next Loop

    now the question,
    with goto your jump to a specific position, while exit for will only break the current for, meaning you need to exit for more than one and make multiple if's

    I would pick goto.

  4. #4

    Thread Starter
    Addicted Member
    Join Date
    Nov 2018
    Posts
    220

    Re: Exiting a Nested For/Next Loop

    OK thanks.

    Just a question as to why Don't manipulate a For-Variable inside the loop! ?

  5. #5
    PowerPoster Zvoni's Avatar
    Join Date
    Sep 2012
    Location
    To the moon and then left
    Posts
    2,133

    Re: Exiting a Nested For/Next Loop

    Because it's bad practice, prone to buggers....errrr... bugs, and if you're not careful, your software is going to cause a nuclear launch in North Korea....
    One System to rule them all, One IDE to find them,
    One Code to bring them all, and to the Framework bind them,
    in the Land of Redmond, where the Windows lie
    ---------------------------------------------------------------------------------
    People call me crazy because i'm jumping out of perfectly fine airplanes.
    ---------------------------------------------------------------------------------
    For health reasons i try to avoid reading unformatted Code

  6. #6
    Frenzied Member
    Join Date
    Aug 2010
    Location
    Canada
    Posts
    1,582

    Re: Exiting a Nested For/Next Loop

    You could also use Do..While loops and test your J & K variables to break out early. It has some annoyances like needing to increment and reset your J & K variable manually, but the advantage is that the conditions for breaking the loop need to be mentally understood only at the Do..While line instead of inside the loop.

    Something like this:

    Code:
    Public Sub Test()
       Dim i As Long
       Dim j As Long
       Dim k As Long
       
       For i = 1 To 10: j = 0: k = 0  ' Reset J & K
          Do While k <> 3 And j <> 10: j = j + 1
             Do While k <> 3: k = k + 1
    
             Loop
          Loop
       Next i
    End Sub
    If you don' like the double-test for k=3, then you can get rid it by adding a "breakloop" boolean variable that is set to True when k=3 and then reset that on each "i" loop. e.g.:

    Code:
    Public Sub Test()
       Dim i As Long
       Dim j As Long
       Dim k As Long
       
       For i = 1 To 10: breakloop = False: j = 0: k = 0  ' Reset Loop Test Variables
          Do While Not breakloop: j = j + 1
             breakloop = (j >= 10)
    
             Do While not breakloop: k = k + 1
                breakloop = (k = 3)
             Loop
          Loop
       Next i
    End Sub
    Loop results with the above match your original loop:

    Code:
    ORIG	NEW 
    LOOPS	LOOPS
    I:1	I:1
    J:1	J:1
    K:1	K:1
    K:2	K:2
    K:3	K:3
    I:2	I:2
    J:1	J:1
    K:1	K:1
    K:2	K:2
    K:3	K:3
    I:3	I:3
    J:1	J:1
    K:1	K:1
    K:2	K:2
    K:3	K:3
    I:4	I:4
    J:1	J:1
    K:1	K:1
    K:2	K:2
    K:3	K:3
    I:5	I:5
    J:1	J:1
    K:1	K:1
    K:2	K:2
    K:3	K:3
    I:6	I:6
    J:1	J:1
    K:1	K:1
    K:2	K:2
    K:3	K:3
    I:7	I:7
    J:1	J:1
    K:1	K:1
    K:2	K:2
    K:3	K:3
    I:8	I:8
    J:1	J:1
    K:1	K:1
    K:2	K:2
    K:3	K:3
    I:9	I:9
    J:1	J:1
    K:1	K:1
    K:2	K:2
    K:3	K:3
    I:10	I:10
    J:1	J:1
    K:1	K:1
    K:2	K:2
    K:3	K:3

  7. #7

    Thread Starter
    Addicted Member
    Join Date
    Nov 2018
    Posts
    220

    Re: Exiting a Nested For/Next Loop

    OK thanks all

    I used the suggestion of using a Boolean

    Below code gets rid of GoTo and gets rid of manipulating For... Next variables inside the loop
    Code:
    Private Sub Command1_Click()
        
        For i = 1 To 10
            
            Dim bConditionMet As Boolean
            bConditionMet = False
            
            For j = 1 To 10
                
                For k = 1 To 10
                    If k = 3 Then
                        bConditionMet = True
                        Exit For
                    End If
                Next k
                
                MsgBox "@ old Goto 100 when i = " & i & " and k = " & k
                If bConditionMet = True Then Exit For
                
            Next j
    
        Next i
        
    End Sub

  8. #8
    PowerPoster
    Join Date
    Feb 2006
    Posts
    20,922

    Re: Exiting a Nested For/Next Loop

    If there isn't any natural way to do the exiting then use a GoTo and be done with it. Even Exit For is just a prettied up GoTo after all.

  9. #9
    PowerPoster kfcSmitty's Avatar
    Join Date
    May 2005
    Posts
    2,177

    Re: Exiting a Nested For/Next Loop

    Sorry for the spam but I felt I needed to post this:


  10. #10
    Fanatic Member
    Join Date
    Dec 2014
    Posts
    969

    Re: Exiting a Nested For/Next Loop

    exactly what dilettante wrote.
    I think adding more variables is worse than using GoTo.
    maybe its not pretty, but I think its easy to understand. GoTo is a very old command and I used it a lot back with commodore 64, later in Amos, and later in pascal.

    and what is that makes it hard to understand a GoTo?
    I think multiple if conditions are more complicated and it looks kludged for me.

  11. #11

    Thread Starter
    Addicted Member
    Join Date
    Nov 2018
    Posts
    220

    Re: Exiting a Nested For/Next Loop

    If there isn't any natural way to do the exiting then use a GoTo and be done with it. Even Exit For is just a prettied up GoTo after all.
    and what is that makes it hard to understand a GoTo?
    I think multiple if conditions are more complicated and it looks kludged for me.
    I agree 100%
    I guess because I've read so many times don't use it I feel compelled to get rid of them

    kfcSmitty

    Thanks all, for help and advice.

  12. #12
    Fanatic Member
    Join Date
    Dec 2014
    Posts
    969

    Re: [RESOLVED] Exiting a Nested For/Next Loop

    yeah, I think the problem with GoTo is if we use it all the time, but not one time in a specific situation.

    example of bad coding:
    Code:
    If Number = 1 Then GoTo Line1 Else GoTo Line2
    Line1: 
     MyString = "Number equals 1" 
     GoTo LastLine
    Line2: 
     MyString = "Number equals 2" 
    LastLine:
    the warning is: Too many GoTo statements can make code difficult to read and debug. from docs.microsoft.com

    but your code is using it 1 time only. so its ok.

  13. #13
    Frenzied Member
    Join Date
    Aug 2010
    Location
    Canada
    Posts
    1,582

    Re: [RESOLVED] Exiting a Nested For/Next Loop

    TBH once we're getting 3 or more loops deep, I'd start looking at moving things out to separate subs/functions with descriptive names so the code almost becomes self documenting. Something like this:

    Code:
    Public Sub Test()
       Dim i As Long
       
       For i = 1 To 10
          ProcessJK i
       Next i
    End Sub
    
    Private Sub ProcessJK(ByVal i As Long)  ' Give this sub a descriptive name
       Dim j As Long
       Dim k As Long
       
       For j = 1 To 10
          For k = 1 To 10
             If k = 3 Then Exit Sub   ' Short-circuit
          Next k
       Next j
    End Sub

  14. #14
    PowerPoster
    Join Date
    Jun 2001
    Location
    Trafalgar, IN
    Posts
    4,137

    Re: [RESOLVED] Exiting a Nested For/Next Loop

    When I've had nested for loops that I needed to escape the outer loop I've just set the outer loop variable beyond the limit of the to statement.
    Code:
    Private Sub Command1_Click()
        
        For i = 1 To 10
            For j = 1 To 10
                For k = 1 To 10
                    If k = 3 Then 
    		    j = 11 ' Set to exit j loop
    		    Exit For
    		End If
                Next k
            Next j
            MsgBox "@ 100 when i = " & i 
        Next i
        
    End Sub

  15. #15
    Frenzied Member wqweto's Avatar
    Join Date
    May 2011
    Posts
    1,815

    Re: [RESOLVED] Exiting a Nested For/Next Loop

    @MarkT: This works but it's usually the code after Next k that must be skipped too.
    Code:
    Private Sub Command1_Click()
        
        For i = 1 To 10
            For j = 1 To 10
                For k = 1 To 10
                    If k = 3 Then 
    		    j = 11 ' Set to exit j loop
    		    Exit For
    		End If
                Next k
                '--- here is code that needs to be skipped
            Next j
            MsgBox "@ 100 when i = " & i 
        Next i
    SkipLoop:
        '--- more interesting code here
    End Sub
    I'll GoTo SkipLoop with no remorses here. After years of experience I'm not afraid of using GoTo at exactly 3 or 4 particular code patterns. Breaking out of nested loops is one of these. Repeating/retrying an operation is another one, for instance GoTo RepeatSend feels natural when dealing with external systems. The simple GoTo Cleanup for error handling is the most used one -- a.k.a. the C-style error handling.

    cheers,
    </wqw>

  16. #16
    PowerPoster
    Join Date
    Jun 2001
    Location
    Trafalgar, IN
    Posts
    4,137

    Re: [RESOLVED] Exiting a Nested For/Next Loop

    In the OP there was no code that needed to be skipped after the k loop.

  17. #17
    PowerPoster Elroy's Avatar
    Join Date
    Jun 2014
    Location
    Near Nashville TN
    Posts
    6,123

    Re: [RESOLVED] Exiting a Nested For/Next Loop

    Personally, I see four approaches to doing this, three that I might use, and one I'd never use. And some (maybe all) of these are mentioned above.

    1. Use an "execute once" Do Loop, making sure no other Do Loops are used down in the nesting, and then make sure that Do Loop has an Exit do as the last statement...

    Code:
    
        Do
    
    
            ' Have as many nested For Next loops as you like,
            ' And execute an "Exit Do" when you want out.
    
    
    
            Exit Do
        Loop
    
    

    2. Create a flag, maybe something like "Dim bKeepGoing As Boolean". And, just before each "Next" statement, check the flag, and, if it's false then execute "Exit Do".

    Code:
    
        Dim i As Long, j As Long, k As Long
        Dim bKeepGoing As Boolean
    
        bKeepGoing = True
        For i = 0 To 9
            For j = 0 To 9
                For k = 0 To 9
    
    
                    ' Do work, maybe setting bKeepGoing to False.
    
    
    
                    If Not bKeepGoing Then Exit For
                Next
                If Not bKeepGoing Then Exit For
            Next
            If Not bKeepGoing Then Exit For
        Next
    
    
    This approach has the advantage that you could actually have multiple "bKeepGoing" flags that broke the nesting at different levels.


    3. With a good understanding of how For Next loops work, you could tamper with your index variables, making subsequent loops terminate. This is quite easy if all of your Step sizes are 1. If you have different Step sizes, this approach can get a bit messy. Here's a straightforward example.

    Code:
    
        Dim i As Long, j As Long, k As Long
    
        For i = 0 To 9
            For j = 0 To 9
                For k = 0 To 9
    
    
                    ' Do work, maybe setting bKeepGoing to False.
                    If WeWantToTerminate Then
                        k = 10
                        j = 10
                        i = 10
                    End If
    
    
    
                Next
            Next
        Next
    
    
    Some may frown on this approach, but I've never seen a language that didn't work in a well behaved way regarding these For Next indexes. They just do the increment (or possibly decriment), hit the Next statement, and check to see if it's over the criterion, and, if so, they exit. The index is always one increment beyond the criterion. For instance, in the following loop, when it's done, i = 10.

    Code:
    
        Dim i As Long
    
        For i = 0 To 9
            '
        Next
    
    

    4. Lastly, I might consider a GoTo. However, there's only one place I actually allow myself to use a GoTo, and that's when a procedure initializes some stuff that needs to be cleaned up. A good example is possibly opening a bunch of RecordSets, that must be closed when we're done. This procedure may have several "escapes". In this case, if I hit one of the "escapes", I'll allow myself a GoTo to jump to the bottom and execute the cleanup.

    I personally don't allow myself to use Gotos in any other circumstance.
    Any software I post in these forums written by me is provided “AS IS” without warranty of any kind, expressed or implied, and permission is hereby granted, free of charge and without restriction, to any person obtaining a copy. Please understand that I’ve been programming since the mid-1970s and still have some of that code. My contemporary VB6 project is approaching 1,000 modules. In addition, I have a “VB6 random code folder” that is overflowing. I’ve been at this long enough to truly not know with absolute certainty from whence every single line of my code has come, with much of it coming from programmers under my employ who signed intellectual property transfers. I have not deliberately attempted to remove any licenses and/or attributions from any software. If someone finds that I have inadvertently done so, I sincerely apologize, and, upon notice and reasonable proof, will re-attach those licenses and/or attributions. To all, peace and happiness.

  18. #18
    PowerPoster
    Join Date
    Feb 2006
    Posts
    20,922

    Re: [RESOLVED] Exiting a Nested For/Next Loop

    I see little advantage in tying your code in knots just to satisfy an artificial principle. Sure, it is easy to fall into the trap of using GoTo as a crutch, and when an obvious alternative exists it should generally be used instead.

    Relying on tricks and subtle side-effects just makes code harder to maintain in the long term as well as impeding portability if you ever need to port to another language.

    That the loop control variable is incremented past the limit value in a For...Next should be considered well known and reliable in VB6, but I wouldn't expect any arbitrary language to act the same.

    I don't see any obvious "winner" among the options, but the simple GoTo has advantages in performance and readability.

  19. #19
    Fanatic Member
    Join Date
    Dec 2014
    Posts
    969

    Re: [RESOLVED] Exiting a Nested For/Next Loop

    I use GoTo a bit,
    when "retrying" something, could be an API or I need to
    example:
    Code:
    Private Sub FigureOutPage(txt As TextSubDataType, ByVal Pos%, ByRef Page%)
        With txt
            If Pos >= UBound(.a) Then Exit Sub
    retry:
            If (Pos + 1) < .Page(Page).begin Then Page = Page - 1: GoTo retry
            If (Pos + 1) > .Page(Page).end Then Page = Page + 1: GoTo retry
        End With
    End Sub
    instead of calling the the function recursively, or use do/while/loops.

    also used when I analyze something, could be a complex data structure with multiple condition checks,
    but if one check is enough to determine something, I "jump" ahead to the next phase.
    exampe:
    Code:
                For i = 1 To sum
                    If data(i).sub.Item = Item Then first = True: GoTo foundAndNext
                    For j = 1 To data(i).nxts
                        If data(i).nxt(j) = Item Then first = True: GoTo foundAndNext
                    Next j
                    For j = 1 To data(i).tras
                        If data(i).tra(j) = Item Then first = True: GoTo foundAndNext
                    Next j
    foundAndNext:
                    If first Then .Count = .Count + 1: ReDim Preserve .Nm(1 To .Count): .Nm(.Count).Id = i: .Nm(.Count).Name = data(i).name: first = False
                Next i
    sure theres multiple ways to do this, but this one is good enough and GoTo is easy to understand.

    not sure why people don't like GoTo and try to avoid it as much possible when its easy to use.
    its like Assembly Jump command.

  20. #20
    Frenzied Member wqweto's Avatar
    Join Date
    May 2011
    Posts
    1,815

    Re: [RESOLVED] Exiting a Nested For/Next Loop

    If one limits GoTo usage to 2-3 well established patterns that are well understood by themselves or their team I see no harm reaping the performance and maintenance gains.

    Here are some 3 cases that might be good candidates for a GoTo in no particular order:
    1. C-Style cleanup
    2. Early exit from nested loops
    3. Repeating a failing operation

    cheers,
    </wqw>

  21. #21
    PowerPoster
    Join Date
    Feb 2012
    Location
    West Virginia
    Posts
    13,090

    Re: [RESOLVED] Exiting a Nested For/Next Loop

    Here is an option, one that I've not used but this thread made me think of it so I'll throw it out there
    Code:
    Option Explicit
    
    Private Sub Command1_Click()
        Dim i As Integer, j As Integer, k As Integer
        For i = 1 To 10
            Do
                For j = 1 To 10
                    For k = 1 To 10
                        If k = 3 Then Exit Do
                    Next k
                Next j
            Loop While k = 0
        MsgBox "@ 100 when i = " & i 
        
        Next i
        
    End Sub
    The code above would effectively do the same thing as your code that has the goto in it
    Of course in your sample loop the J loop doesn't really do anything so no reason for it to even be there as the next j statement will never execute.

Posting Permissions

  • You may not post new threads
  • You may not post replies
  • You may not post attachments
  • You may not edit your posts
  •  



Featured


Click Here to Expand Forum to Full Width