Why is using GoTo considered bad practice?

tmyers

Well-known member
Local time
Today, 02:37
Joined
Sep 8, 2020
Messages
1,091
I have a few small modules where I have used If Then Goto statements (mostly for filters) as, at least to me, it is easier to read in a logical sense as you test for various conditions. However I have had several people tell me that using GoTo is a big no no but no one has told me why as of yet. I could see it being bad in large code blocks as it could make following what is happening when reading it very difficult.

Anyone have insights as to why I am being told this is bad practice and should avoid doing it?
 
Hi. Maybe try searching for the term "spaghetti code."
 
Ah yes I am familiar with that term (even though most of the time I hear it used incorrectly).
So my seemingly simple (and what I thought easy to read) is considered bad practice. I will have to correct that then.

Here is what I was doing:
Code:
Private Sub PriceFilters()

Dim strfilter As String

    If Me.MfrFilterTxt > "" And Me.PartTxtBx > "" Then GoTo Line1
    If Me.MfrFilterTxt > "" Then GoTo Line2
    If Me.PartTxtBx > "" Then GoTo Line3
    If Me.MfrFilterTxt = "" And Me.PartTxtBx = "" Then GoTo Lastline
    
    
Line1:

    strfilter = "[Manufacturer] like '*" & Me.MfrFilterTxt & "*'"
    strfilter = strfilter & " AND [Part] like '*" & Me.PartTxtBx & "*'"
    GoTo Lastline

My mind read that very easily, so I did not think it was bad but can see why it would be considered such.
 
Then I suppose the next question would be is there an even more "correct" method then:

Code:
If Me.MfrFilterTxt > "" Then
        
        strfilter = "[Manufacturer] like '*" & Me.MfrFilterTxt & "*'"
        Me.PriceHistorySubFrm.Form.Filter = strfilter
        Me.PriceHistorySubFrm.Form.FilterOn = True
        Me.PriceHistorySubFrm.Form.OrderBy = "[DateEntered] Desc"
        Exit Sub
        
    Else
    
        strfilter = ""
        Me.PriceHistorySubFrm.Form.Filter = ""
        Me.PriceHistorySubFrm.Form.FilterOn = False
        Exit Sub
        
    End If

I just more or less repeat this and change the IF statement to look at what the controls contain. Should I go on step further and return strfilter as a variable into another subroutine?
 
With help from a friend it has been turned into:

Code:
Private Sub PriceFilters()

Dim strfilter As String
        strfilter = ""
        Me.PriceHistorySubFrm.Form.Filter = ""
        Me.PriceHistorySubFrm.Form.FilterOn = False

    
    If Me.MfrFilterTxt > "" And Me.PartTxtBx > "" Then
        strfilter = "[Manufacturer] like '*" & Me.MfrFilterTxt & "*'"
        strfilter = strfilter & " AND [Part] like '*" & Me.PartTxtBx & "*'"
    ElseIf Me.MfrFilterTxt > "" Then
          strfilter = "[Manufacturer] like '*" & Me.MfrFilterTxt & "*'      "
  ElseIf Me.PartTxtBx > "" Then
         strfilter = "[Part] like '*" & Me.PartTxtBx & "*'"
End If
    
If Not IsEmpty(strfilter) Then
        Me.PriceHistorySubFrm.Form.Filter = strfilter
        Me.PriceHistorySubFrm.Form.FilterOn = True
        Me.PriceHistorySubFrm.Form.OrderBy = "[DateEntered] Desc"
End If
        

End Sub

That looks so much better than the giant IF blocks I was doing.
 
This could end up being a good thread so I'm interested as well what others have to say about this. My own take is that using the goto's somewhere else unnecessarily, causes you to to scroll somewhere else on the code page to find out what that condition is actually doing. So you might know what it does, but someone else looking at the code doesn't and is force to maneuver around. In a regular subroutine that flows straight down the block of code logically, this is not the case. Look up "Collocation" in context of programming to learn more. It becomes even more interesting when mixed with object oriented code.

I see you posted an updated version which is more in line with standard procedural coding.
 
With help from a friend it has been turned into:
I usually design such a code a little differently - 4 lines per search field, and any combination of fields, for numeric fields and date fields of the beginning / end of the period, there are small changes in the code (there are no quotes or there are #)

moreover, only one boundary of the interval can be given or the condition OR is applied

Code:
Private Sub PriceFilters()

    Dim s1 As String, s2 As String
    ''''''''''''''''''''''''''''
    s2 = Trim("" & Me.MfrFilterTxt)
    If Len(s2) > 0 Then
        s1 = s1 & " and [Manufacturer] like '*" & s2 & "*'"
    End If
    ''''''''''''''''''''''''''''
    s2 = Trim("" & Me.PartTxtBx)
    If Len(s2) > 0 Then
        s1 = s1 & " and [Part] like '*" & s2 & "*'"
    End If
    ''''''''''''''''''''''''''''
    If Len(s1) > 5 Then
    Me.PriceHistorySubFrm.Form.Filter = Mid(s1, 5)
    Me.PriceHistorySubFrm.Form.FilterOn = True
    Me.PriceHistorySubFrm.Form.OrderBy = "[DateEntered] Desc"
    End If
    ''''''''''''''''''''''''''''
End Sub
 
With help from a friend it has been turned into:
And my "two cents" :
Code:
Private Sub PriceFilters()
Dim strFilter As String

    If IsNull(Me.MfrFilterTxt) = False Then
        strFilter = strFilter & " AND [Manufacturer] like '*" & Me.MfrFilterTxt & "*'"
    End If
    
    If IsNull(Me.PartTxtBx) = False Then
        strFilter = strFilter & " AND [Part] like '*" & Me.PartTxtBx & "*'"
    End If
    
    If Len(strFilter) > 6 Then
        ' First (in begining of string) " AND " - out!
        strFilter = Mid(strFilter, 6)
        Me.PriceHistorySubFrm.Form.Filter = strFilter
        Me.PriceHistorySubFrm.Form.FilterOn = True
    Else
        Me.PriceHistorySubFrm.Form.Filter = ""
        Me.PriceHistorySubFrm.Form.FilterOn = False
    End If
End Sub
 
I have a few small modules where I have used If Then Goto statements (mostly for filters) as, at least to me, it is easier to read in a logical sense as you test for various conditions. However I have had several people tell me that using GoTo is a big no no but no one has told me why as of yet. I could see it being bad in large code blocks as it could make following what is happening when reading it very difficult.

Anyone have insights as to why I am being told this is bad practice and should avoid doing it?
I remember using Go To a lot with COBOL, then Structured COBOL was the preferred method and Go To was only allowed to go to the end of the procedure.
 
However I have had several people tell me that using GoTo is a big no no but no one has told me why as of yet.
many years ago, when I was a young specialist, I was given a task to understand the program
, it was spaghetti 20+ pages of 72 lines, which means more than 1500 lines
- absolutely uninformative variable names like a1,a2,.....k1,k2
- in addition to the usual labels, there were a lot of re-assigned labels (there are none in ACCESS)

it was something, I didn't understand
anything, after a few days I decided to draw a flowchart on a 82cm* 60cm watman, it's about 3 by 2 feet, 8 ordinary sheets of paper

after making half of the scheme, I realized that the tree has about 30 conditions of 20 lines with access to the formation of an reports with the addition of headers and signatures

yes, I rewrote it by introducing procedures and functions, the program decreased by 3 times, but it became absolutely transparent for understanding and reading

GOTO also remained in it to exit to the end of processing from the next condition

it was only after 2-3 years that I got acquainted with a book by a German author about structural programming, while I did not find anything new for myself
 
Last edited:
I wrote COBOL for 30 years with NO GoTo's. That was structured programming. GoTo's are not necessary. I was a convert then and haven't changed my opinion yet and so still do not use them except for error handling. Like VBA, the problem with CICS was that it handled errors badly so you could not avoid using GoTo's. At a minimum, you had to GoTo the error handler.

Keep in mind that COBOL is not event driven so you had a mainline that was an outline of the process and essentially a list of Perform's (GoSub's). The exit from the program was at the end of the mainline.

I use GoSub's in VBA to organize long procedures or for code that will be reused within the sub or function. Code that is reused by other parts of an application need to be subs or functions defined in standard modules.
 
I wrote COBOL for 30 years with NO GoTo's. That was structured programming. GoTo's are not necessary. I was a convert then and haven't changed my opinion yet and so still do not use them except for error handling. Like VBA, the problem with CICS was that it handled errors badly so you could not avoid using GoTo's. At a minimum, you had to GoTo the error handler.

Keep in mind that COBOL is not event driven so you had a mainline that was an outline of the process and essentially a list of Perform's (GoSub's). The exit from the program was at the end of the mainline.

I use GoSub's in VBA to organize long procedures or for code that will be reused within the sub or function. Code that is reused by other parts of an application need to be subs or functions defined in standard modules.
Oh yes, CICS Command Level. Translated to a zillion Go To's. AWFUL!
 
Coming as I did from an Assembly Language environment (device drivers for DEC PDP-11) and some other aseembly environments, I never used a GOTO because it was a JUMP (or JMP or BRANCH or pick another word - and they usually did). But TRUST me, they WERE necessary at that time.

My main complaint regarding GOTO is that there are times for exit/abort conditions where you have incredibly complex nesting of IF ladders or SELECT CASE (or COMPUTED GOTO from FORTRAN) where a GOTO helps to deconvolute the spaghetti. (How did Alexander untie the Gordian Knot? He cut through it ignoring its loops!) Modern languages so do much better than the early 3rd-generation languages with loop control and (what used to be called) alternation control, and thus have drastically reduced the number of situations where that radical level of deconvolution is so beneficial - and necessary.

I would also suggest that for some of those earlier "high-level" languages, GOTO was the "get out of jail free" card. It took a while for some of those procedural languages to add the escape hatches like EXIT FOR or EXIT DO etc. As those were added, the need for GOTO diminished. But we got here by a gradual improvement, not an overnight switch from REALLY dumb languages to smarter languages. I would suggest that if you don't like GOTO but DO use EXIT FOR, EXIT DO, early EXIT SUB, etc. then you are playing at semantics. You have replaced one verb for another.

Therefore, I am a believer in GOTO only when too many options present themselves and the convolution factor even WITHOUT the GOTO becomes too complex to follow. Before anyone says "just design it better" I ask you to remember that the situation drives the program; the programmer doesn't always drive the situation. But I agree that the number of GOTOs required to do things is reducing dramatically.
 
" I ask you to remember that the situation drives the program; the programmer doesn't always drive the situation."

That sounds too much like common sense. :unsure:
 
@tmyers
It is very common in Access VBA to do something like you are doing and build concatenated strings for filters, sql, rowsources, etc. There are lots of techniques but the trick is to handle one or more conditions that does not have a value. You have to do one thing if it has a value or another if it does not. You can do this trick where you remove an And or OR from the beginning or remove something from the end. I find it just a lot easier to use this construct.

Dim str as string
..
Code:
if str = "" then
   Do something
else
  str = str & do something
end if

As you loop or check controls, you simply check if the concatenated string has been populated.
I added a third case to be a little more descriptive

Code:
Private Sub PriceFilters()

Dim strFilter As String
Dim Mfr as string
dim Part as string
dim frm as access.form

Mfr = Me.mfrFiltertxt & ""
part = me. PartTxtBx & ""

If mfr = <> "" Then
  strFilter = strFilter & "[Manufacturer] like '*" & Mfr & "*'"
End If

If Part <> "" Then
  if strFilter = "" then
       strFilter = strFilter & "[Part] like '*" & Part & "*'"
  else
       strFilter = strFilter & " AND [Part] like '*" & Part & "*'"
   end if
End If

If SomethingElse <> "" then
  if strFilter = "" then
     strFilter = strFilter & "[Something] like '*" & Something & "*'"
  else
      strFilter = strFilter & " AND [Something] like '*" & Something & "*'"
  end if
end if

set frm = me.priceHistorysubfrm.form
frm.Filter = strFilter
frm.FilterOn = (strFilter <> "")

End Sub



A couple minor issues that can make writing code easier. Short is not necessarily better, but it can create less chance of error.

1. If you reference a long object more than once, consider a variable instead of repeating

add a variable for pricehistorysubform.form

Code:
dim frm as access.form
set frm = me.pricehistorysubform.form

then just use frm throughout

2. If the result of an "if then" causes a switch from a true condition to a false condition you can make a "toggle" with one line of code

Code:
If Len(strFilter) > 6 Then
  Me.PriceHistorySubFrm.Form.FilterOn = True
Else
   Me.PriceHistorySubFrm.Form.FilterOn = False
End If

to simply

Code:
frm.filteron = len(strFilter) > 6


3. You do not have to set the default values of variables
Code:
Dim strfilter As String
strfilter = ""

That second line makes no sense. A string defaults to "", numbers to 0, objects to null, booleans to false.

4. Empty controls are usually NULL not "". They can be "", but that is rare and you have to force that to happen.

This is not a good check since rarely = ""
Code:
Me.MfrFilterText = ""
Better is:
Code:
If isNull(me.mfrfiltertxt)
Even better is:
Code:
If (Me.mfrfiltertext & "") = "".
This checks both empty cases (null and "")
The best checks is probably
Code:
Trim(Me.mfrTextFilter & "") = ""
That checks a third case of one or more spaces.
Never do If
Code:
Me.mfrFilterText = NULL
Does not work.
 
If the result of an "if then" causes a switch from a true condition to a false condition you can make a "toggle" with one line of code
@MarkK schooled me on this recently and this works quite nicely now that I understand it. It was very confusing the first time I seen it.
 
many years ago, when I was a young specialist, I was given a task to understand the program
Kind Galina: "many-many years ago ... " - when? - first PC is just from 1983 (if I remember correctly)
You are too young to say so, many happy years to you!
...
Have you ever calculated the shortest distance (more then 300 miles on the surface of the Geoid) on the Great Circle Arc by a logarithmic ruler? :)
 
Last edited:

Users who are viewing this thread

Back
Top Bottom