Anyone besides me remember programming in BASIC with GoTo, GoSub, line numbers, and Returns? We wrote some great programs that way, but the difficult maintenance that followed is what gave birth to the term "spaghetti code." Well, Microsoft QuickBasic rescued us from this by offering BASIC programmers a way to do structured programming with functions. Then Visual Basic later brought us into the modern era with object-based, event-driven programming.
So all that old spaghetti code stuff is dead, right? Wrong! All four of these beastsGoTo, GoSub, line numbers, and Returnsare still alive in VB6. Don't believe it? Copy and paste the code from Listing 1 into a button click handler in a VB6 application and try it!
Listing 1: VB Spaghetti Code
10 GoSub 30 15 MsgBox "2" 20 GoTo 50 30 MsgBox "1" 40 Return 50 End
It's a sad fact, but I ran into legacy code as part of a project in 2000 that made extensive use of GoSub and Return! GoSub and Return have finally been dropped in Visual Basic .NET, but line numbers are still around and kicking in VB (although they are automatically converted to labels in VB .NET.)
I'll be the last one to shed tears over the passing of GoSub and Return, but this article demonstrates a good use for line numbers and an accompanying functionErlthat has been in VB (but has been undocumented) all along. By the way, Erl is still in VB .NET as of Beta 2 as a (still poorly documented) property of the Err object.
A Debugging Headache
A common problem when debugging VB components is unhelpful error messages. A classic example is "Runtime error 429: ActiveX component can't create object" being raised from a component's Class_Initialize method, which itself instantiates several other components (see Listing 2). This error is difficult to track down because the error could be coming from any of the Set statementsand, indeed, may well be originating from a lower-level dependency that you don't even know about.
Listing 2: Class_Initialize Code That Is Difficult to Debug
Private Sub Class_Initialize() Dim ErNum, ErDesc, ErSrc On Error GoTo ErrHandler Set m_FormStr = CreateObject("FPIWebForms.CConCat") Set FPIFormInfo = CreateObject("FPIFormInfo.CFormInfo") Set FPIctrl = CreateObject("FPIFormInfo.CControlInfo") Set FPIininfo = CreateObject("FPIInputInfo.CInputTableInfo") Set InSymTab = CreateObject("FPISymTab.CSymTab") Set FPIininfo.setSymTab = InSymTab InSymTab.AliasPrefix = "in_" FPIininfo.Initialize_CSymTabArray Set CM = CreateObject("FPIClientMgr.CClientMgr") Set CalcSymTab = CreateObject("FPISymTab.CSymTab") CalcSymTab.AliasPrefix = "ca_" CalcSymTab.InitializeSymbolTable 1000 Set DataSymTab = CreateObject("FPISymTab.CSymTab") DataSymTab.AliasPrefix = "da_" DataSymTab.InitializeSymbolTable 1000 Set Calc = CreateObject("FPIEval.CCalc") Set Util = CreateObject("FPIUtility.CUtility") Util.SuppressUI = True Set Eval = CreateObject("FPIEval.CEval") Set Eval.InputInfo = FPIininfo Set Eval.CalcRef = Calc Set Eval.Utility = Util Eval.AddSymbolTable DataSymTab Eval.AddSymbolTable CalcSymTab Eval.AddSymbolTable InSymTab Exit Sub ErrHandler: ErNum = Err.Number ErDesc = Err.Description ErSrc = Err.Source & ", CFormHTML.Class_Initialize" Err.Raise ErNum, ErSrc, ErDesc End Sub
However, the judicious use of VB line numbers and the Erl function can help make problems like this a little easier to solve.