PDA

View Full Version : Exiting Top Level For Each from nested For Each



gmaxey
01-18-2011, 09:48 AM
I should probably know better, but I asked anyway. What is the recommended method of eixting a top levef For Each loop when a condition is met in a nested For Each loop:

Sub ScratchMacro()
Dim i As Long
Dim j As Long
Dim k As Long
Dim l As Long
Dim m As Long
i = 0
For j = 1 To 10
For k = 1 To 10
For l = 1 To 10
For m = 1 To 10
i = i + 1
If i = 1000 Then Exit For 'I want to exit "all" For loops.
Next m
Next l
Next k
Next j
MsgBox i
End Sub

Thanks.

fumei
01-18-2011, 10:00 AM
Logically, an Exit instruction it is either:

A) the immediately loop

OR

B) everything, i.e. the Sub.
Sub ScratchMacro()
Dim i As Long
Dim j As Long
Dim k As Long
Dim l As Long
Dim m As Long
i = 0
For j = 1 To 10
For k = 1 To 10
For l = 1 To 10
For m = 1 To 10
i = i + 1
If i = 1000 Then
MsgBox i
'I want to exit "all" For loops.
Exit Sub
End If

Next m
Next l
Next k
Next j
MsgBox i
End Sub

macropod
01-18-2011, 02:13 PM
Hi Greg,

I'm sure you know this:
Sub ScratchMacro()
Dim i As Long, j As Long, k As Long, l As Long, m As Long
i = 0
For j = 1 To 10
For k = 1 To 10
For l = 1 To 10
For m = 1 To 10
i = i + 1
If i = 1000 Then Goto Done
Next m
Next l
Next k
Next j
Done:
MsgBox i
End Sub

gmaxey
01-18-2011, 02:36 PM
Paul,

Ten years or so ago when I first began cobbling together elementary procedures some nasty, but good, VBA coder blasted me for using GoTo in my code (except Error Handling). I can honestly say to this day that I don't know why, but it was one of those things that stuck, so I have pretty much applid it as gospel and don't even think about it in case like this.

Considering what I had done shown below, maybe it isn't so bad after all:
bFound = False
For Each rngStory In ActiveDocument.StoryRanges
'Iterate through all linked stories
Select Case rngStory.StoryType
Case 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11
Do
For Each oCurrentCC In rngStory.ContentControls
If Selection.Range.InRange(oCurrentCC.Range) Then
bFound = True
Exit For
End If
Next oCurrentCC
If bFound = True Then Exit Do
'Get next linked story (if any)
Set rngStory = rngStory.NextStoryRange
Loop Until rngStory Is Nothing
Case Else
End Select
If bFound = True Then Exit For
Next rngStory


I'll be interested in seeing who else comes out for and against using GoTo:014:

macropod
01-18-2011, 02:50 PM
Hi Greg,

I think the aversion to Goto is a hang-over from the old GWBASIC days, when well-structured code was well-nigh impossible and Goto statements littered the code. The stuff was almost unreadable (great for code obfuscation, though:whistle:). As you've observed, Goto statements are often used in VBA as part of an error-handling routine - you could think of the example I posted as being a way to handle a deliberate 'error'.

PS: With your Case statement, why not:
Case 1 to 11

gmaxey
01-18-2011, 03:22 PM
Case 1 To 11

Just another tree in a forest that I didn't see.. Thanks.

fumei
01-19-2011, 10:04 AM
I was going to mention using a final GoTo as an alternative. It is quite legitimate.

Paul_Hossler
01-22-2011, 03:16 PM
Using the Err object


Option Explicit
Sub ScratchMacro()
Dim i As Long
Dim j As Long
Dim k As Long
Dim l As Long
Dim m As Long
i = 0

On Error GoTo LastOne

For j = 1 To 1000
For k = 1 To 1000
For l = 1 To 1000
For m = 1 To 1000
i = i + 1
If i = 1000 Then Call Err.Raise(vbObjectError + 1000, "ScratchMacro", "Got to 1000")
Next m
Next l
Next k
Next j

Exit Sub

LastOne:
If Err.Number = vbObjectError + 1000 Then
MsgBox "Got to 1000 --- " & i
Call Err.Clear
Exit Sub
Else
Resume Next
End If

End Sub


Paul

gmaxey
01-23-2011, 04:22 AM
Paul,

Thanks. I have used Err.Raise in a different manner and certainly agree taht it could be used here as you have show. However, in view of Paul and Fumei's beliefs that GoTo itself isn't so back this now looks like over kill. Would you agree?

fumei
01-24-2011, 09:55 AM
IMO, there is nothing wrong with using GoTo at all. In well structured/written code it is simply a redirection.

Paul_Hossler
01-24-2011, 01:31 PM
Greg -- I agree with Gerry about a well used GoTo (at least I'll agree for the next 240 hours :) )

Personal Opinion:

Your intended usage is most likely low risk, since

1. there is only one statement that GoesTo it; multiple statements that GoTo it could be a maintenance/debug issue.

2. The proximity of the destimation is 'close' to the jump statement in the code; GoTo-ing a location several screens away could be confusing

3. I had thought about a Do While construct, but decided that it was more confusing and that the reason for a GoTo would be clearest a year from now when you came back to the code

Paul

fumei
01-24-2011, 01:46 PM
I wholeheartedly agree with all of Paul's points, especially #1 and #2. My own personal opinion is that if the GoTo instructions are more than 20 lines from the pointer it may - but may not - be a good idea to look at further redirection via formal subroutine.

Of course the main issue with THAT is that you may have to pass parameters (objects or variables) to those subroutines. Which of course brings in Scope.

However, IMO, the advantages of easily readable and debug-able (is that a word?) code far far outweigh any disadvantages. Besides, it is excellent practice in writing object-oriented code.

Also, I tend to avoid any procedures greater than 60 lines of instruction. Sure the overall set of instructions can be many times that, but unless you are really good at writing code (and ALWAYS comment things...), it is better to make procedures in testable chunks.