Previous | Index | Next 

[PRB] GoSub statements inside For loops and With blocks cause a compilation error

VB6 supports the GoSub statement, whereas VB.NET doesn’t. The GoSub statement isn’t structured and is a symptom of poor programming, therefore we recommend that you edit the original VB6 code to replace GoSubs with calls to methods and arguments.

At any rate, in its quest to deliver VB.NET code that “just works,” VB Migration Partner is capable to correctly translate GoSub and On GoSub statements in most circumstances, by transforming them into GoTo statements and by maintaining a return address stack. For example, consider the following VB6 code:

 
        Sub Test(ByVal first As Integer, ByVal second As Integer)
            Dim index As Integer            
            ' show the first index
            index = first
            GoSub ShowIndex            
            ' show the second index
            index = second
            GoSub ShowIndex
            Exit Sub
        ShowIndex:
            Debug.Print index
            Return
        End Sub

This is how the above code is converted to VB.NET:

 
        Sub Test(ByVal first As Short, ByVal second As Short)
            Dim _vb6ReturnStack As New System.Collections.Generic.Stack(Of Integer)
            Dim index As Short = first            
            ' show the first index
            vb6ReturnStack.Push(1): GoTo ShowIndex
        ReturnLabel_1:            
            ' show the second index
            Index = second
            vb6ReturnStack.Push(2): GoTo ShowIndex
        ReturnLabel_2:
        Exit Sub
		
        ShowIndex:
            Debug.WriteLine(index)
            GoTo _vb6ReturnHandler
            Exit Sub
		
        _vb6ReturnHandler:
            Select Case _vb6ReturnStack.Pop()
                Case 1: GoTo ReturnLabel_1
                Case 2: GoTo ReturnLabel_2
            End Select
        End Sub

The resulting VB.NET code works flawlessly, but it’s apparent that it is neither readable nor maintainable, hence our recommendation to revise the original VB6 code and manually transforms GoSubs into method calls. If you decide to rely on VB Migration Partner for automated translation of GoSub and On GoSub statements, though, you must be aware of a minor limitation of this technique, which manifests itself when the GoSub is located inside a For or For Each loop, as in this code:

 
        Sub Test(ByVal first As Integer, ByVal second As Integer)
            Dim index As Integer
            For index = first To second
                GoSub ShowIndex
            Next
            Exit Sub
        ShowIndex:
            Debug.Print index
            Return
        End Sub

This is the converted VB.NET code:

 
        Sub Test(ByVal first As Short, ByVal second As Short)
            Dim _vb6ReturnStack As New System.Collections.Generic.Stack(Of Integer)
            Dim index As Short
            For index = first To second
                vb6ReturnStack.Push(1): GoTo ShowIndex
        ReturnLabel_1:
            Next
            Exit Sub
		
        ShowIndex:
            Debug.WriteLine(index)
            GoTo _vb6ReturnHandler
		
            Exit Sub
		
        _vb6ReturnHandler:
            Select Case _vb6ReturnStack.Pop()
               Case 1: GoTo ReturnLabel_1

            End Select
        End Sub

When you compile this code, the VB.NET compiler produces the following error:

 
        'GoTo ReturnLabel_1' is not valid because 'ReturnLabel_1' is inside 
        a 'For' or 'For Each' statement that does not contain this statement.

The reason is, you can’t jump into a For or For Each loop from the outside. A similar problem occurs when a GoTo statement points to a label inside a With...End With block.

Short of getting rid of the GoSub statement – which, once again, is the recommended strategy -, the only way to avoid this error is by transforming the For loop into the equivalent Do While loop. For example, the previous VB6 code might be rewritten as follows:

 
        Sub Test(ByVal first As Integer, ByVal second As Integer)
            Dim index As Integer
            Index = first
            Do While index <= second
                GoSub ShowIndex
                index = index + 1
            Loop
            Exit Sub
        ShowIndex:
            Debug.Print index
            Return
        End Sub

The above migrates and runs correctly under VB.NET. Similar transformations can be performed with For loops with negative steps or with For Each loops.

Similarly, if the GoSub statement is located inside a With…End With block, you have to get rid of the block and ensure that object references that start with a dot are fixed accordingly. For example, assume that you start with this VB6 code:

        Sub MoveControl(ByVal ctrl As Control, dx As Integer, dy As Integer)
            With ctrl
                .Left = .Left + dx
                GoSub DoSomething
                .Top = .Top + dy
            End With
            ...
            Exit Sub
        DoSomething:
            ...
            Return
        End Sub

Here’s how you should revise the code to get rid of the With…End With block before attempting to migrate it:

        Sub MoveControl(ByVal ctrl As Control, dx As Integer, dy As Integer)
            ctrl.Left = ctrl.Left + dx
            GoSub DoSomething
            ctrl.Top = ctrl.Top + dy
            ...
            Exit Sub
        DoSomething:
            ...
            Return
        End Sub

 

Previous | Index | Next