Comments

You must log in or register to comment.

Sloloem t1_iyalbym wrote

The idea that "Goto statement considered harmful" came from an essay by Dijkstra that was published in 1968 during the dawn of computer science.

His basic case was that GOTO was too primitive to have a single easily understood function when seen in code. It tells the machine to arbitrarily move control to a different instruction at a different line of the program but says nothing about why or what's going to be there. Also since you need to physically start reading somewhere else in the code with the context of what's in memory from the previous location in mind it can make programs extremely hard to read and verify, especially in an age before IDEs and debuggers. It allowed for too wide of a gap between the mental model of a static program and a dynamic running process.

He advocated instead for what he called "structured programming" which is really just programming as anyone born after maybe 1964 understands it. Structured programming makes extensive use of this new-fangled idea from the late 50's called "blocks", because someone had to invent the idea of:

if (true thing) {
    doThings();
}
else {
    doOtherThings();
}

at some point.

With blocks that's just the way you write that code with the instructions immediately blocked inside the condition that allows their execution to proceed. With GOTO those lines could be 600 lines away. And without another GOTO to send you back to where you left off, you'll just keep going from wherever you ended up until the program exits or crashes.

GOTO also predates a lot of the looping structures we take for granted in modern programming and while it could be used to implement them, using the actual loops instead carries more meaning and makes your program easier to read, understand, and compile (compilers that translate human-readable source to machine-readable machine code can make certain optimizations in how it feeds instructions into the CPU...as long as it understands what the loop does). So at this point while a lot of the readability issues would be countered by modern tooling, the adoption of more structured ways of writing code and more nuanced looping statements makes goto...kinda pointless.

360

generous_cat_wyvern t1_iyayncx wrote

>He advocated instead for what he called "structured programming" which is really just programming as anyone born after maybe 1964 understands it.

I don't know why this part made me laugh so much! But yeah, it was revolutionary at the time, but now it's considered very basic fundamentals.

46

Sloloem t1_iybi5pc wrote

Yeah I kindof had a moment when I realized that paper was so old it predates not only C, but also C's predecessor B...and we still talk about it. I'd worked in languages without loops before and actually had to use goto's and labels to reproduce the flow control of while and for loops when I was first learning so I just assumed the concepts had always existed in programming. It's a really interesting history how we got from doing math real fast to programming a world-wide near-real-time communications network so we can look at cat videos on the toilet. ...If you're into that sort of thing, I guess.

24

OldHellaGnarGnar2 t1_iyb9od3 wrote

This is the first explanation I've read about this topic that made me understand it.

The robots we have at work had their code written by an integration company we use. The first 1-2 hundred lines of each program is "where to go next", with a bunch of

>if (all these conditions match) GOTO {section that handles whatever is supposed to happen next}

It's always a huge pain whenever I'm writing new code to add or improve functionality, and trying to check that I didn't introduce any new possible states where it can't figure out where to go - because I have to jump from line 50 to 400 to 30 to 670 to 30 to 900 etc.

Having the function directly follow the "if" condition seems like it would make more sense.

Question for you: if I want to improve my coding skills (because I only took one class in school, and have just picked other stuff up as I go), would it be a good exercise to re-write all their code using the structure you've outlined? And/or if I'm trying to learn another language like python specifically, see if I can re-write it in that, so I can learn that syntax & commands at the same time?

42

Sloloem t1_iybovkb wrote

Yikes, I'd actually seen code kindof like that written by outsourced contractors for a financial services firm I used to work for. They created these "god" functions that ran through multi-step processes by wrapping the whole thing in a giant for loop and using If's on the iterator like if (i==1)... (i==2)... (i==3) to block each step. It really hampers extensibility.

> Question for you: if I want to improve my coding skills (because I only took one class in school, and have just picked other stuff up as I go), would it be a good exercise to re-write all their code using the structure you've outlined?

Assuming you're talking about re-writing the IF-GOTO code your robots use in more structured style, yeah absolutely. Changing the underlying implementation of some functionality while maintaining its public contract is actually the definition of "refactoring". Being able to cleanly refactor code and write code that's cleanly refactorable are actually the underlying goals of a lot of current best-practices in Object-Oriented programming so it's definitely an important skill to practice.

> And/or if I'm trying to learn another language like python specifically, see if I can re-write it in that, so I can learn that syntax & commands at the same time?

Porting code directly like that is an interesting activity but maybe something that's more of an intermediate activity once you have the fundamentals down. I thought this phrasing was kind of pompous when I first heard it but most languages have "idiomatic" ways of doing some things that is considered the correct way to write code in that language. Of course the languages are flexible enough that they would allow you port structure and style of another language's idioms to this new language, but those sorts of idiomatic patterns usually come out of some key feature of the language and have fundamental advantages in terms of code expressiveness or performance. So it's best to learn "Pythonic" ways of writing code that might be very different from how someone who'd trained as a Java or C++ developer would usually think of implementing them. Then once you feel like you can write Python, you can try re-implementing functionality that used to be written in some other language and paradigm in Python rather than trying to re-write some Java using Python. It's a slight language shift but I think it's a good way to frame it.

In a professional setting you're also unlikely to see a company trying to do a 1:1 re-write of an existing product. The switch in tech stack is usually driven by a desire to benefit from some killer feature of the new stack like NodeJS's fast async I/O or something else, and to do that you usually need to write idiomatically and respect the eccentricities of the language and the framework.

22

OldHellaGnarGnar2 t1_iyce8wd wrote

Thanks for the feedback! I've never heard of refactoring, but I guess that's exactly what I was trying to describe.

>In a professional setting you're also unlikely to see a company trying to do a 1:1 re-write of an existing product.

True, however my goal with trying to write it in another language wouldn't be for actual implementation; it would be to try to start learning a new language. I only really know Matlab and Fanuc TP (the robot language I was talking about). I'd like to learn a more widely used language so I can potentially open doors to more types of jobs than I'd currently be qualified for.

4

[deleted] t1_iycqx12 wrote

[removed]

4

OldHellaGnarGnar2 t1_iycxv3j wrote

That makes sense. While I was thinking about how to do what we're talking about above, I hadn't yet come up with a solution to "what about when I need it to skip to the end for a mid-process cycle stop," and thought I still might need a GOTO for that, to exit the loop at those interruptions.

3

Sloloem t1_iyeh3if wrote

Controlling flow from inside loops is done with break and continue.

Something like this:

for (i=1;i<=10;i++) {
  if (i==5) SOMETHING
  print i;
}

If you use break for SOMETHING your output is: 1 2 3 4

If you use continue your output is: 1 2 3 4 6 7 8 9 10

Some languages let you control multiple levels of looping using something like break 2 to break not only this loop, but the loop it's inside. Javascript lets you do this with labels. Not all languages give you this level of control so you either figure out how to design the process without nested loops or come up with other ways around the issue like GOTO's or flag variables that direct outer loops to break when set from inner loops but those situations have no single right answer.

2

OldHellaGnarGnar2 t1_iyehcc0 wrote

Do these work similarly for while loops?

2

Sloloem t1_iyehp37 wrote

Oh yeah. Totally.

2

OldHellaGnarGnar2 t1_iyf5swx wrote

I'm not sure if I missed your link about breaks earlier, or if it was edited in, but I just now saw it, and it's super helpful. Our robot programs technically use "JMP LBL", not GOTO, but I basically took them as the same thing in terms of function. So it already has labels for each section if I were to restructure it to use nested loops and whatnot.

All of your comments have been super helpful. I've been wanting to learn more programming for a while, but wasn't sure what concepts or practices I'm not even aware of, and this gives me a lot to think about. I recently got the "Automate the Boring Stuff with Python" book, to use as a starting point, but am still kinda learning the syntax and python-equivalent commands of what I already know in Matlab of Fanuc TP, and haven't really gotten to stuff about code structures or paradigms, etc

2

Sloloem t1_iyf986x wrote

Sweet deal, glad I could help and good luck breaking in.

Actually I just scoped out some of your comment history and see you're working in CNC engineering and pop into physics and CAD subreddits a lot...I have an idea for a hand-cranked guitar pickup winder I'd like to design for 3d printing but for some reason I'm having a hell of a time getting my head around how to design the gearbox to multiply RPMs in a reasonable size. A guitar pickup involves upwards of 10,000 winds of a copper filament around the magnetic pole pieces. Motorized pickup winders tend to have speed controls from 600 to 2000 RPMs but for a hand-cranked machine 500RPM seems downright reasonable. We're talking <2oz balanced load. Is that something that might be in your wheelhouse that you could point me at some good resources or fundamentals about? Because I'd love to learn it.

2

Sloloem t1_iyeb96m wrote

I was speaking mostly to a mindset difference in how you approach the new language.

You'll be better at Python in the long run if you start from the description of what a program is supposed to do and treating the original code itself as a black box rather than trying to translate Matlab syntax to Python syntax because knowing the language is more than just knowing the syntax, you need all those idiomatic expressions. Python has some interesting collection structures and ways of manipulating those that I don't know if Matlab has direct equivalents for, so learning how to use them is just as much of learning Python as learning the syntax.

Honestly being curious about how programming works at all is a trait I wish more developers had so that puts you above half the people I've interviewed for jobs.

4

OldHellaGnarGnar2 t1_iyeh3yo wrote

Ahh, ok that makes a lot of sense. So, rather than doing a one-to-one translation, figure out how I can take advantage of python's capabilities vs whatever language I'm trying to convert code from.

Secondary question:

Is your comment related at all to programming paradigms? Like, I think all the code I know how to write would be considered "functional" (I didn't learn anything about paradigms in school), so after seeing some discussion on paradigms and watching some videos, I'm trying to understand "when would I use object-oriented" or another paradigm. So maybe if I learned to write in a different paradigm, it could be a better fit than what I'd be able to write in functional?

2

Sloloem t1_iyeqfi9 wrote

Yeah exactly, to both points. Learning how to do similar things under different paradigms is a great skill because it keeps you from getting too stuck on one way to approach a problem but learning all the available paradigms is mostly an academic exercise. You can learn the paradigms to identify their influences on languages but unless you're going into language design or academia they can be pretty esoteric. Not very many languages are purely single-paradigm. Most languages take influence from multiple paradigms and include features from those that designers like, creating fairly unique ways of expressing program instructions.

Example off the top of my head would be something like Scala. Scala adds features of the Functional paradigm to the Java language which is very Object-Oriented in its design. So if you're writing Scala you can write it like OO code, Functional code, or a mix of both. Scala idioms prefer Functional approaches so if you use those you tend to write less code and stuff runs better but you can also work with objects and gain some benefits of OO concepts like function encapsulation.

Python is another language that takes hints from Functional programming and OO programming, but implements its objects and classes very differently from how Java does it.

3

SuperBelgian t1_iye7700 wrote

There could be a reason for such a structure. Financial institutions often still have very old esoteric hardware, such as mainframes. (Even if not actively used, they still need to keep it functional to access archived data.)

Just, because you can program and compile something without errors, doesn't mean it will run correctly.
Nested functions, calling a function within a function, which calls a function, etc... is a very common way of doing things.
However, some CPUs have a limit on how deep such a stack can go, going as low as to only 4 or 8 stacks deep. (Ex: Arduino.)
Very old hardware doesn't even have such a stacking possibility that allows nested functions.

2

Sloloem t1_iyed84i wrote

That's all true, you're absolutely right. I was just trying to keep my anecdote from getting too lengthy by leaving out details...in this case the code in question was written in Java in 2009 and running on IBM WebSphere on contemporary datacenter hardware so there were really better ways to have laid it out. Maybe the robots are stack limited which makes sense, but refactoring it is still a good thought experiment if nothing else.

2

Unable-Fox-312 t1_iycdti9 wrote

If you can get paid for it, definitely.

You should read the basic docs for your language first, though. Find out what people consider the book and study it, then take on that project in bitesize chunks with tangible goals. See if you can refactor 5% of the functionality and still have a working robot. Then 10%. If you plan to flip a switch and go from 0 to 100 on the job you're setting yourself up for a forever project and ultimately failure

5

OldHellaGnarGnar2 t1_iycf6rr wrote

>If you can get paid for it, definitely.

>If you plan to flip a switch and go from 0 to 100 on the job you're setting yourself up for a forever project and ultimately failure

If I were to refactor the code, I'm not sure it would ever actually be implemented. The robots have been working correctly for a few years, so I doubt management would want to "fix" what isn't broken, and potentially mess what has already been working.

If I did this, I think it would purely be an exercise for me to get better at coding. After a couple years at this job, it turns out I like writing code more than almost anything else, but that's a really small part of my current job - so my goal would be more of "get better at programming and/or learn a new language, so I can be more employable in positions that are more programming-focused"

7

Kriemhilt t1_iycsjrt wrote

The normal term for "the burden of working with rubbish code that is hard to understand or change" is technical debt.

One of the advantages of calling it that is that it sounds sort-of like financial debt, so you're putting it in language management might find easier to understand. You ideally want some concrete motivation though, like

>"technical debt will make it slower (and therefore more expensive) to add these features you want, but if we invest in reducing our technical debt first, those features will arrive sooner and have fewer bugs."

If they don't have any bugs to fix or features to add, this obviously doesn't help you much!

4

OldHellaGnarGnar2 t1_iycyqk2 wrote

Good advice!

>If they don't have any bugs to fix or features to add, this obviously doesn't help you much!

But that's the issue I think I'll have if I try to push it. Our robots generally just work as-is, and most of what we have to add is parameterized, so we're mostly filling in variables and not actually writing code. Actually writing new code for bug fixes or new functionality is pretty rare (I think I'm the only one that's learned how to do it since our division implemented robots).

About a year ago (first time I actually wrote new functionality for them), my boss and I had to convince management I was capable of adding in a new safety feature that got brought up as something we should do.

2

Symbian_Curator t1_iycacc6 wrote

I just want to point out, GOTO is not completely pointless, but the industry is used to repeating how GOTO is terrible without thinking much about the reasons, the reasons being as you pointed out, but also, valid uses for GOTO are so few and far between that it's just easier to teach new programmers to simply never use it.

About those valid uses:

  • In C, to mimic the destructor behaviour of C++ in function. For example, let's say that in function F you have: initialize resource A, initialize resource B, initialize resource C, do some work, clean u C, clean up B, clean up A. Then, in the code, you would try to init A, and if it works, carry on, but if not, exit the function. Try to init B, and if it works, carry on, but if not, GOTO "clean up A" part. Try to init C, and if it works, carry on, but if not, GOTO "clean up B" part. When you GOTO like this, the code "falls through" to clean up only the resources which were initialized. I was told that this technique is used widely in the code of the Linux kernel, but honestly I haven't bothered to check myself.
  • With some compiler extensions, computed GOTOs (where you can take the address of a GOTO label, put it in a lookup table, and jump based on some index) present a optimization opportunity for performance critical code, notably interpreters for other languages or bytecode of other languages. (it's similar to switch/case, just faster)
11

Deadmist t1_iycd9gz wrote

> In C, to mimic the destructor behaviour of C++ in function.

That doesn't mean using GOTO isn't bad, it just means that there is no better option in C.
In 'modern' languages, like C++ or Java, you can achieve the same outcome with destructors or try-with-resources, without the pitfalls of GOTO.

10

Symbian_Curator t1_iyce7cl wrote

I agree, but sometimes you just have to use C and then you use the tools you have. A bad tool is better than no tool at all.

My main point was that GOTO is not always pointless/useless.

6

Clewin t1_iyd736l wrote

Speaking of, one of the biggest uses of GOTO I saw in C was for exception handling. C++ as well, until try-catch blocks were added (and that varied by compiler until the late 1990s, early 2000s).

2

Liese1otte t1_iyd0xn1 wrote

Yea, this. GOTO is not neccessarily a bad thing. It's a thing. More popular codebases (mostly lower level) use GOTOs than people think. It can be handy in rare cases when you are in control and using GOTO won't actually hurt readability / predictability.

It's just that it's really easy to fuck up when using GOTO so you might as well just not at all (especially when you are not an expert on how things tend to work with it).

Same can be applied to other commonly accepted opinions, like using "eval"-type commands.

6

Sloloem t1_iyefdj8 wrote

Some languages also kindof have you using GOTOs and labels for exception handling...I wanna say Visual Basic? I did a project a few years ago using CrownPeak CMS which at the time I think used VB for its templating language and I vaguely recall winding up with a lot of really snotty "ON ERROR GOTO HELL" clauses. I think some legacy data applications that had a lot of functionality written in SQL procedures used that sort of error handling instead of more modern try-catch-finally or try-with-resources blocks. It's all true but I don't think I'm inaccurate in saying they're pretty niche edge cases for most programmers.

1

Symbian_Curator t1_iyefzmc wrote

At this point, Visual Basic itself is a niche edge case :D

2

Sloloem t1_iyehs4b wrote

And we're all the better for it being that way.

1

Mike2220 t1_iyc605t wrote

>And without another GOTO to send you back to where you left off, you'll just keep going from wherever you ended up until the program exits or crashes.

jal and jr have entered the chat

3

Sloloem t1_iyebsgt wrote

Man I am not gonna throw down with an assembly programmer. They scare me a little, flying so close to the sun.

1

Mike2220 t1_iyehm15 wrote

I needed to learn it for a few classes

It was a time

2

Sloloem t1_iyes9ij wrote

Heh. I graduated in 2009 and we still had some assembly in my degree program. It wasn't even being taught in a specific CPU's assembly language at that point, they had invented some assembly-like language to teach us about registers, bitmath, and jumps but it was actually interpreted by a Java CLI tool that produced the output.

I think it was just there to teach us how good we have it working at higher levels of abstraction.

1

Mike2220 t1_iyezgz8 wrote

Oh we had to do stuff with MIPS on one of those development boards

Took like 10 tries to actually upload the program to it even if your code worked, it sucked

2

Coincedence t1_iyclmnt wrote

There are certain situations where GOTO makes sense. I've had to use once or twice to do thins like restart a loop arbitraily where you have go back to a parent loop that may be 3 or 4 times removed. Its not ideal, and in nearly every case there are better alternatives, but GOTO is still valid sometimes

2

Chasman82 t1_iyd959l wrote

Very clear answer. It resulted in a major improvement in programming quality, since it was easier to debug and maintain. I recall that either Dijkstra or someone else illustrated the point by building some code to perform a simple task but using COME FROM instead of GOTO. The code was incredibly difficult to understand and drove the point home.

2

Sea_no_evil t1_iydi3g8 wrote

Yes. IOW, Goto is a primitive instruction not too far removed from the assembly language -- the native language of the chipset itself. As programming languages get more sophisticated, the need for goto goes away. The fact that most languages still have a goto instruction is really more about history than function.

2

cabbeer t1_iyd86ow wrote

Wow, you’re really good at explaining programming… what would go to look like in JavaScript? Or is that not possible because it’s single threaded?

1

Sloloem t1_iydwukt wrote

GOTO would work fine in a single threaded environment, you can't use it in javascript just because javascript doesn't have a GOTO statement. If it did it would probably look the same as it does anywhere that does have it where you pair GOTO some_label with a line of code reading :some_label to give the GOTO a target line. Not sure why they didn't include it.

1

tezoatlipoca t1_iyahosc wrote

Its not necessarily, if used correctly. PRoblem is it was arbitrary and prone to abuse; it is (or was, no one uses it anymore) lazy programming in languages higher than assembly.

Usually we want to branch code execution based on some criteria.

IF condition THEN
 do these things
OTHERWISE
 do other things
END IF 
do some necessary cleanup

This way there's a controlled return from the branching. We only have two routes: do these things or the other things. There are no other options or possible routes for execution.

By controlling or containing the execution this way we know that regardless of whether we do these things or other things, we'll ALWAYS wrap up afterward with the necessary cleanup (which might be really important.)

If I throw a random GOTO in there,

IF condition THEN
 do these things
OTHERWISE
 do other things
 GOTO XANADU
END IF 
do some necessary cleanup

#XANADU 
 do some unrelated stuff
 get lost

unless I explicitly end that goto with another GOTO that returns me to where I left off, I might never return. We'll never do the necessary cleanup for example.

Using GOTOs allowed you to jump ANYwhere. I could jump into the middle of other branches I could jump out of loops willy nilly; yeah, this is still allowed with break statements but at least the break statement just exits the loop, a GOTO could warp you anywhere. So very powerful... but it also lets programmers be lazy. Code getting too complicated? Can't find a way to structure it properly so error and failure cases return you to someplace sane? Meh, bash a GOTO in there. Its like a magic code ticket that takes you to where you want to go with no (and by that I mean all the) consequences (unallocaed memory, initialized/uninitialized variables, who knows).

A GOTO is like a magic airline ticket that takes you anywhere in the world. Except when you get there you may not have any luggage. Or both feet.

139

Megalocerus t1_iyb9mpc wrote

In COBOL the goto didn't even have to specify the destination. You could do an ALTER and have it go somewhere else. Try reading that.

GOTOs are bad but ALTER is Satanic.

15

carlovski99 t1_iyc60gq wrote

2

Megalocerus t1_iydadd3 wrote

Yes, that's far worse, but I never encountered that in real code. The rules for using alter were:

  1. Don't use it.

  2. If you use it, have any GOTO referenced by it leave off the destination in code. Thus, it was just GOTO. by itself on the line with a period, to clue the programmer it was a trap.

1

Existing-Metal-5211 t1_iydidtc wrote

Naw... I did some stuff like that in basic by poking the basic code with destination. I cannot recall why I didn't use on goto for that project tho.

1

Intergalacticdespot t1_iyc1xkw wrote

If you're writing BASIC (well apple][e/c64 era basic) it's not. You don't really have a choice. Now...probably is and not sure what youd even use it for other than some lazy hackish stuff.

2

AustinJeeper t1_iyb0jrq wrote

sooooo, function() ?

i think the main issue is more like

  • IF condition Then
    • do this stuff
    • #Xanadus
      • do some shit
    • do shit only needed at fall through
  • Else
    • other stuff
  • end if

#goto Xanadu

it lead to horrible references.

−1

Nagisan t1_iybirhz wrote

> sooooo, function() ?

Not exactly.

Functions return to the point of execution once they finish running, GOTO just continues running the program linearly from where ever in the code the GOTO is pointing to.

For example, if the comment you replied to used a function instead of GOTO XANADU, the 'unrelated stuff' would run, then it would return to the spot it left off on, which would run the 'necessary cleanup'. But GOTO doesn't do that, GOTO would run the 'unrelated stuff' and then just hit the end of the file and never clean up.

GOTO is a one-way operation that sends the program to another line of code and never returns (unless you explicitly program another GOTO that goes back), functions send the program to another line of code but then return back to the line the function is called from once the function is done.

9

Deadmist t1_iycdnze wrote

Functions ^1 also give you a well defined arguments, return type(s) and scope for variables.
With GOTO, there is no guarantee for anything.

^1 in most languages, looking at you JS...

2

A_dudeist_Priest t1_iydg0si wrote

I am an old fart developer that learned on the old PET's, C64 and TI, the language I learned on, was BASIC\Waterloo BASIC (we are talking early 80's here), GOTO was a staple. I have watched languages go from a "wall of code", to the more structured OOP that we use today.

You brought up and interesting point that I had never thought of, when calling a Function\Subroutine, everything in the calling function is pushed onto the stack, then popped from the stack when returning from the called function, the GC would then "clean up" as you say. But I guess using a GOTO statement would not push and pop the stack, would/could this cause a modern application to have a memory leak, or cause the application to run out of process and/or Heap space?

A hint for beginner developers, be careful of recursive function calls (functions that call themselves) if done improperly, you get into a recursive loop and you will very quickly run out of stack space.

1

Nagisan t1_iydgn4p wrote

I would guess it could cause memory leak issues and such, but in all honesty I'm not much for low-level programming details beyond what I did through school and much prefer sticking around the web dev space these days....so I'm not entirely sure the full implications that GOTO would have on memory.

1

generous_cat_wyvern t1_iybqmwc wrote

>functions send the program to another line of code but then return back to the line the function is called from once the function is done.

Except for when Exceptions are thrown, but I guess that's why they're called Exceptions :p (I actually don't know if that's the reason, I probably just made that up) But even Exceptions propagate up a call stack in a predictable manner.

As an aside, it blew my mind when I found out that in ASP.NET, redirects happen by internally throwing a ThreadAbortException behind the scenes that can't be handled by normal means. It made sense that code after calling redirect didn't execute, and the only way to have code behave that way is if an Exception is thrown, I just never put two and two together.

0

Nagisan t1_iybrn9u wrote

Exceptions can open up a whole pandora's box in the flow of a program. I can't speak for every language (because there's lots I don'tknow), but at least with what I'm most familiar with the function does return to the line it was called from depending on how you handle the exception.

In the case of your function catching the exception, you can fail gracefully by logging an error, at which point the program will continue and the function will return to the line that called it then just chug right along (if the result of the function wasn't necessary for the program to continue).

In the case your function doesn't catch the exception, it will bubble up to the place it was called from and repeat this process (if the exception is caught at the higher level, my second paragraph happens, otherwise it bubbles up again, repeat until something catches the exception or the program reaches the main function and crashes).

So yeah, exceptions can be the oddity here, but they also can continue to work the same as no exceptions when it comes to the flow through a program.

1

Dunbaratu t1_iyatoyo wrote

First you have to understand how it was originally used, then understand what replaced it, then you can understand why it's not used anymore.

The ability to skip ahead or skip back to a different line of code lets you do a great many things. It's generic and open-ended what it can do. When you create a way to do it conditionally where it won't always execute the goto then it allows for all the standard flows we use today.

An If-block is really just "If this condition isn't true then GOTO the spot just past this block so you skip over it."

An unconditional loop is really just "GOTO a previous line up above so you start executing all this stuff again. When you get back down to this line, GOTO the top again. Repeat."

A conditional loop is really just "IF the thing we're checking for to end the loop isn't true, then GOTO a previous line and run that stuff again."

It's versatile. It can form just about any pattern.

So what's the problem? Well that versatility IS the problem. To understand why a programmer put a GOTO there, to understand what they were trying to do, you have to analyze a lot more lines of code to see what the pattern was. Because a GOTO could really be for a wide variety of purposes. It might be part of an IF. It might be part of a WHILE (thing is true) loop. It might be part of an UNTIL (thing is false) loop. It might be part of a counting loop (FOR loop). It might be to just jump over to a subroutine and return from it.

It's not visually obvious from just looking at it what it's for. You have to trace the code line by line before you can see the big zoomed-out picture of the layout.

It also allowed unique flow patterns that don't fit into one of the commonly known patterns. A clever programmer could have been using it to do something unique that only makes sense in their own mind and doesn't make sense to anyone else.

So, essentially, it can make the program hard to understand, which then means programmers make mistakes when editing it.

The fix was to find all the common things people were using GOTO to do, and create special keywords for those patterns and replace the use of GOTO with those new terms. So you can still do all the same stuff, but in a more descriptive way that actually says what you're doing. You don't have to guess "Which of the 8 or 9 different reasons for using a GOTO might this one be?" when it uses a word like WHILE or FOR or IF that actually tells you which one it is.

But the interesting thing is... under the hood, it's still really all GOTO. At the lower machine language level, you have the various JUMP instructions, which are exactly what a "GOTO" would have compiled into, and as it turns out, is also what the newer words like WHILE and FOR and IF also still compile into.

Under the hood, it's still all GOTO. But now it has more descriptive ways to summarize those GOTOs into human-readable structures.

16

Menolith t1_iyah8ka wrote

Mostly just because they make a mess out of the flow of the program. Modern languages have tools you can use to perform complex logic with a syntax that doesn't seemingly arbitrarily hop all over the code to get things done.

GOTOs were useful in the early neolithic era when Grog first invented COBOL and the concept of a "loop" was novel, but nowadays there are better options. If you find yourself in need of using one, chances are that whatever structure you have in mind can be represented in a way which doesn't need a GOTO.

14

dosadiexperiment t1_iyc7bxz wrote

It's what you tell beginners to keep them from making too much of an unmaintainable spaghetti mess, which is what people will generally end up with if they think of it as a general-use tool in their toolbox, instead of merely for a few specific narrow situations. But it's not quite as absolute as it's usually presented.

The Linux kernel uses gotos in a structured way that's helpful. (If you're using C++, you should probably instead use RAII to do what they're doing, but in C careful use of goto can be worthwhile to get a similar effect.)

Some would claim breaking out of multiple levels of nested loops also is a good use case, and produces code that's easier to read than trying to chain breaks through multiple loops. Common wisdom is you're better off putting your loops in a function and using 'return' when you need this, but it's a debatable point when goto is in the language.

5

gliderXC t1_iyahx8m wrote

It becomes very hard to manage the order of execution of parts of your program. Normally with a function, you call it and you return. With a "goto" you just go forward (and no return). It is prone to result in so called spaghetti code which is often buggy (and it is hard to read -> hard to maintain).

Note that the construct is not inherently evil. It is just the structure of the code that is undesired.

4

petersrin t1_iyborbp wrote

"Not inherently evil" And in fact we still use something similar regularly for certain types of error handling.

3

[deleted] t1_iyathy7 wrote

GOTO is considered an anti-pattern because it introduces non-linear control flow into a computer program - computer programs are generally written with linear control flow.

GOTO allows you to jump to any location in your program without any respect for how you got there - it's basically one-way teleportation.

Being able to teleport anywhere without respect for the structure of a given computer program allows you to do virtually anything regardless of how you got there, and, this leads to people doing a lot of weird things just because they can.

This is really the only reason why its use is considered an anti-pattern, and there's nothing wrong with using GOTO if you really know what you're doing.

Generally speaking you should stick with established well-known control flow semantics to make your program as easy to read as you can.

3

schmal t1_iybvisk wrote

It's actually GREAT practice! How else can you write this little gem in beginners all-purpose symbolic instruction code: 10 Print"Hello lovely!" 20 Goto10

2

severoon t1_iyc0yst wrote

It's not a bad practice because it's impossible to use it in a way that avoids problems; it's considered bad practice because it's possible to use it in a way that causes problems.

This is often the case in programming. You'll find that people will argue that such-and-such is okay because "if you just use it correctly, there's no problem." But correct usage isn't always straightforward, and the less straightforward it is, the more problems there are.

Ideally, a perfect programming language would provide only constructs that make it impossible to represent unintended things. In fact, this perfect programming language actually exists in theory! It would be a programming language which requires formal proofs of all possible functionality. This sounds absurd, but in reality, even though it's impossible, it's less impossible than it at first seems because you can do things like method guards and early escape returns, which reduce the space of test cases from virtually infinite to merely unmanageable and totally unrealistic (for real systems, not toys).

Example time. Say that I want to write a method that can multiply integers from 1 to 10. A first year student in coding 101 will write something like:

/** Return product of a and b. */
int mult(int a, int b) { return a*b; }

…and feel proud that they not only addressed the requirement, but produced something much more general purpose that will also work for any two integers.

How silly and naive. What they failed to account for is that this doesn't actually work for any two inputs, and if you were to exhaustively test every single combination of 32-bit inputs, you'd find a large number of them that result in overflow conditions (like a = b = max int). But that's okay, it still does the thing it's supposed to for the expected inputs, so what's the problem? The problem is that since you specified a looser contract for this method than was required, you have not addressed just the requirement but the looser contract you chose to support (because of Hyrum's law).

If you actually restricted the contract to just the requirement:

/** Return product of a and b if both are between 1 and 10 (inclusive). */
int mult1to10(int a, int b) {
  if (a &gt; 0 &amp;&amp; a &lt;=10 &amp;&amp; b &gt; 0 &amp;&amp; b &lt;= 10) { return a*b; }
  // do some crazy ish
}

In design-by-contract rules, if you don't specify in the contract what a method does, then it is unspecified, meaning that you can literally do anything and still be in compliance. You could go into an infinite loop. Call System.exit(9). Whatever.

Because everything is allowed when a or b are outside the specified bounds, it's super easy to prove that this method formally complies with its contract. The space of the inputs is so small you can even practically write a set of exhaustive tests, and you could also formally prove using lambda calculus or whatever based on the code as written that it does exactly what it says it does.

What does this have to do with your question? What I'm doing here is introducing these notions of formal proof and exhaustive testing not because it's practical, but rather to connect the idea of "covering the entire space of possible inputs" with the ability to reason about code. In mathematics we have this notion of continuity, whereby we say a function is continuous if the outputs transition smoothly from one value to another if the inputs transition smoothly from one value to another. Now just because these transitions are smooth doesn't mean that outputs don't move around in an absolutely wild and unpredictable way, but for a lot of functions you can make strong statements that outputs definitely don't do that. You could have a function where you prove that it it's monotonically increasing, and the increase in the output is proportional to the increase in the input (y = 5x, for instance), so you'll never see weird or erratic behavior in the output for a steady increase in the input.

See where I'm going with this? If you write methods that behave like simple mathematical functions that are easy to reason about because they are constrained in particular ways, then we don't need to exhaustively test every possible combination of inputs. We can say, for example, that if you put in a 1 and get a 5, and you put in a 100 and get a 500, that's good enough to assume if we put in something between 1 and 100 we'll get something between 5 and 500. But you can only say this if your function behaves like y = 5x and isn't trying to tell you angles of Foucault's pendulum or some chaotic process.

This was the problem with the simple code we wrote in the first example above. Given a simple requirement, we decided to tackle the entire class of inputs and wound up with an output that has significant areas of discontinuity (int overflow). We could solve that problem by returning a long, and now we can say that, hey, it's now a simple method we can reason about. Problem solved! Right? Right???

Not really. Clients ruin everything.

The problem is still not solved if what clients really need is an int. Remember, we're writing this method according to some contract not just to occupy our time; presumably we have callers we are trying to support. If we're going to change the contract by returning a long instead of an int, we had better be darn sure that change does not diminish the utility of the contract!

If it does, and clients actually need an int, then what they're going to do is cast that result to an int. If they screw this up by not checking for overflow, then we have not really solved a problem, we just relocated it. Even if they don't screw it up and they do all the correct bounds checking, we are putting extra work on each and every client that we could centralize in one place … and that's the whole point of doing this work in the first place, right? I mean ,couldn't callers just do the multiplication themselves too? Why ever provide any API that does anything?

So there's no escape. As a provider of an API, your job is to provide a contract that meets the need of the caller, and do it as correctly as possible. That's a good API.

But as we see from the above two examples, when we did a seemingly innocuous thing, we introduced unexpected behaviors into our implementation. It's really, really easy to do because it's really, really hard to write code that's really, really easy to reason about.

And, finally, at long last, we go way back up to the top of this post and reread what I wrote there: Good practices are good not because they make it possible to do the right thing, but because they make it impossible to do the wrong thing. Ideally. In practice, the best you can do is make it harder to do bad things, and easier to do right things.

And that's why goto is bad. There is nothing you can do with a goto that you can't also do with other programming constructs minus the big ol' footgun that goto hands you because these alternatives all come with additional restrictions on how control flow is handled that make them easier to reason about.

2

tzaeru t1_iyco5g2 wrote

I'll add a little bit of philosophy and theory to this:

The general trend in the development of paradigms, rules and methodologies has been to restrict the programmer from doing certain things. goto lets you arbitrarily move to a different place in the code. This can be made less arbitrary by forcing the programmers to use functions and loops.

Similarly, encapsulating variables is a restriction. It restricts easy access to the variables from outside the class.

Type safety is a restriction. It forces assignment and other operators to require explicit casting for variables of different types.

So on, so on.

Without restrictions, the programmer could do anything at any time and it would be extremely difficult to read such code. When you restrict things, you force the code from different programmers to be more easily understandable and you (hopefully) decrease the amount of bugs in the code.

Sometimes you create a restriction that makes it hard to express some things in a clean way. For example, in C, goto still has a place in error checks and in ensuring that an error causes a function to release the resources it initialized at the start of the function. In more modern languages, there really isn't any reason to ever use goto, since the languages offer other more powerful (and more restricted!) constructs for dealing with the issues that goto is used for in C.

2

immibis t1_iyam8iu wrote

It's easier to understand something when all the pieces are next to each other in a straight line. You tell the computer to do this, then this, then all of these, then frobnicate the widgets, then pass the salt. When you see a loop, you know the computer is going to repeat what's in the loop a certain number of times, then do the stuff after the loop.

"goto" lets you tangle up the pieces as much as you like. The problem is not the word "goto" itself, but it is the fact that if you didn't create a tangled mess then you'd be able to write it without the word "goto". An otherwise straightforward program with one or two "goto"s is often still understandable, but when you have many of them, it can be hard to understand exactly what the program is doing, e.g. you might not even be able to work out how many times a certain line of code gets run.

Note that when Edgar Dijkstra wrote his famous letter "Go To Statement Considered Harmful" in 1968, structured programming with instructions like "if" and "while" were somewhat new and people weren't using them as much as they could have.

Ironically, many programmers write the exact same kind of mess with classes and methods, and think it's good because there's not a single "goto".

1

PooPartySoraka t1_iyb34q0 wrote

is "frobnicate" something you made up or a term you heard somewhere else? is it popular? i fkn love it it made me think of "rekafoobulating the energymotron" from futurama and i'm gonna use it all the time xD thank you

1

immibis t1_iyb4c7v wrote

it's a pretty common placeholder verb

1

BrickFlock t1_iyawmv3 wrote

There are usually easier to read options that structure the code better. The most common valid use for it is jumping out of nested loops.

1

lynxerious t1_iyaywme wrote

The flow of the program is determined by your imperative or declarative programming. You do things once by once or declare what would happen if an event occurs.

Goto messes up this flow and makes the code way harder to track. It gives programmers too much freedom, they need to be constrainted by shackles or eveything gonna be catastrophic once day.

1

[deleted] t1_iyb0nkf wrote

[removed]

1

explainlikeimfive-ModTeam t1_iyciq2q wrote

Your submission has been removed for the following reason(s):

Top level comments (i.e. comments that are direct replies to the main thread) are reserved for explanations to the OP or follow up on topic questions.

Anecdotes, while allowed elsewhere in the thread, may not exist at the top level.

If you would like this removal reviewed, please read the detailed rules first. **If you believe it was removed erroneously, explain why using this form and we will review your submission.

1

virgilreality t1_iyb1b8v wrote

Other constructs return control to the thing that called them, keeping the line of processing much much clearer.

The alternative is what we call "spaghetti code", where determining the true path through the code is damned near impossible...like trying to follow a strand of spaghetti through an entire bowl of it.

1

Defleurville t1_iybba9x wrote

Structured programming code can generally be read from any position, in either direction: If you find a train car on a track, you can check what it went through before by following the track towards where it came from.

A Goto works closer to a Starfleet transporter: When you find a train car on the track, it might just have teleported in there from wherever. If there are traces of an ambush a mile up the track, you have no idea if that train car went through it.

Goto is a tool which often allows you to do something easily instead of doing it right.

For example, maybe Goto would make your program work now, but it will make it harder to resolve bugs and if there are later changes they could be much harder to implement.

1

mgstauff t1_iybfgl0 wrote

I used GOTO like candy in the early 80's with Microsoft BASIC! But otherwise, I've been coding professionally since 1996 and have used GOTO exactly once and that was last year actually, to jump to some error handling code in a particularly dense and multi-faceted set of conditionals. It seemed like the cleanest way to handle things, and it was within the same function of course so pretty reasonable.

1

trutheality t1_iybj9ay wrote

Control structures like if/else statements, while loops, and for loops place the code that is executed when the condition is true or false in predictable places, and more importantly, (unless there was an early return or a thrown exception), the control flow always returns to the line after the end of the (for example if/else) block when the conditional part is done. Goto has no such guarantees: it could send you to some arbitrary line earlier or later in the code and the only way to figure out if you ever come back is to go see if some other goto sends you back. Using gotos also means that there could be parts of your code that don't really make sense unless you know what gotos send you there.

As a result, gotos can make your code very hard to understand by inspection, and it also means that it's easier to make mistakes when writing code with gotos. That's not to say that it would be impossible to write readable code with gotos, but if you put all your conditional logic in predictable patterns, you're probably structuring it the same way you would using if or while statements anyway.

1

magick_68 t1_iyc0z2u wrote

In the old times there was only goto. And it led to really bad code. Then there was a time where using goto was considered extremely bad programming.

I've seen a lot of places where gotos make sense. Mostly (if not always) in error handling where gotos can actually clean up convoluted code when you can't use exceptions for some reason.

1

DTux5249 t1_iyc6i19 wrote

The issue is that "goto" plops you somewhere in the program, but with little to no way back.

Programming practice likes consistency, and linear flow. Every line is an instruction, and should be followed in sequence.

Even if I have to say, call a method from somewhere else in the code, I'm still sitting in the same place. I can leave where I am, go do whatever, then come back and continue where I left off. Clean.

"Goto" though? I could've jumped 5 lines ahead, or 269, and I have no way back. It's obscenely reckless in large programs, making them an absolute pain to edit, and it's just lazy in smaller programs.

1

BirdUp69 t1_iyce9ub wrote

My probably out of date understanding is that goto ignores stack management. Stack allocated in the current context would remain allocated wherever the goto ends up. Done repeatedly this will lead to a stack overflow.

1

pdpi t1_iyckqgh wrote

GOTO is one of a handful of really fundamental, core concepts in programming, you basically can’t achieve anything useful without it. The flip side to that is that, because you need GOTO for everything, you need to read a lot of the surrounding code to understand what, exactly, you’re trying to achieve.

As it turns out, there’s a small handful of uses (if/else, while, for, try/catch, function calls) that completely dominate compared to everything else. Instead of a goto that can mean anything, you can use one of those language constructs instead and say exactly what you mean (this is also why most languages are slowly adopting for x in list, because it’s the most common usage pattern for for loops). This is easier to read, it’s less error prone (because the compiler/interpreter can handle all the setup and cleanup chores for you).

People do forget that there is a long tail of legitimate use cases for goto, though, which is a bit of a shame.

1

2wicky t1_iycqzzr wrote

I remember GOTO in combination with line numbers made maintaining or adding new features in Basic a nightmare. It's hard to tell which lines are being jumped into, meaning that by changing a line of code, you can invertedly break the program flow if you are not paying close attention to any gotos pointing at it.
To avoid this, you avoid changing any existing code that works by jumping around it. All this jumping around then results in a difficult to follow flow.

Using a bad but simple example of spaghetti code:

10 let a = 10

20 let b = "spaghetti"

30 print b

40 let b = "pasta"

50 let a = a + 10

60 if a &lt; 60 then goto a

70 print "code!"

While clever, "spaghetti" shouldn't be printed twice. The right thing to do is rewrite this entire block of code, but you can't really do that if this is part of a larger program with other parts jumping into it as you could risk breaking other parts of your program.
So instead, using the above method of coding around problems, a bug fix could end up looking like this:

10 let a = 10

20 let b = "spaghetti"

30 goto 50

40 let b = "pasta"

50 print b

55 let a = a + 10

60 if a = 20 then goto 40

70 print "code!"

Not very pretty at all.

1

eddfredd t1_iyd8y4g wrote

It's the difference between teleporting to your destination and actually walking to your destination. Both gets you there but by walking you have an idea of how you got there.

1

Existing-Metal-5211 t1_iydhxaj wrote

Literally because one guy said so and others latched onto it. It's like he never wrote in ML/ASM at the time. Nothing wrong with goto, its not bad. There are bad usages of course. I look at the "goto bad" folks as dumb asses following an unvetted religious assertion, and I'd love to see them program in ML. Their code would be bloated shitware.

What is more important is to document, especially strings, and complex functions. I found an old phreak tool/code hacker I wrote in 1988 on a the scene database. The gotos are not what makes it hard to follow. It's my various string handlers and no documentation of my variables.

Structured programming is a great idea; but not necessary for readable or useful code. Further, this religious bullshit killed many of the 'i program for myself' coders by making simple things more complex. Good programming means understanding the tools you have and implementing them to serve your desired ends. Goto allows for smaller code in certain situations, along with easier to read code in others. As line numbers were replaced with labels (like in qb4.5) readability options also increased.

10 print "i love goto! ";
20 goto 10

or

home
print "i still love goto! ";
goto home

TLDR: some jackass who didn't consider ML said something stupid about spaghetti code and readability and people took it as religious fact.

1

parautenbach t1_iyenm8u wrote

There's been some great explanations, so I'll add something else.

Programming languages can also be ranked according to how close they are to the hardware. Assembly code is at a pretty low level where it directly gets translated to machine code. Assembly code contains e.g. jump instructions which is a more basic version of a goto statement. Anybody that has coded like this knows it can get pretty complicated quickly — as mentioned by others. That's what you have, so you need to use it, but you can build higher level abstractions where you don't directly need to deal with it (higher level languages, function calls, etc.).

Now, in many old games (like running on DOS), a popular hack was to disassemble the code and then insert jump statements to get around password or other checks. This is one place where it was useful, albeit perhaps illegal in some cases. This is also potentially useful for code where you don't have the source to recompile it, but need to fix something (I don't have an example at hand, but it has happened).

Lastly, it also gets used in a form of hacking known as ROP (return oreinted programming).

1

HockeyCookie t1_iyagot4 wrote

Dedicated branches are unnecessary. You don't create a turn in the road for no reason. It will just cause the driver to lose their way. Someone that has to fix the code will often lose their way of there are unnecessary turns in the road.

0

d4m1ty t1_iyawjyg wrote

Often, people rely on goto and get lazy when coding.

Goto is fine when there is no other option and you need to do some spaghetti.

0

Milnoc t1_iybikwv wrote

I use goto, but only sparingly. I use them to get out of complex nested loops or switch/cases and jump either to the end or to the beginning of a function where I would have a maintenance routine to clean up before leaving the function or to reinitialize and restart the nested loop.

If you start using gotos where they're not needed at all, you're just asking for trouble down the road.

0

xzt123 t1_iybn96i wrote

What language? In Java you can label the loop and break out of the loop by name.

In C#, your use of goto is probably ok. C# has more rules about goto, it can't be anywhere and I believe it can't skip variable definitions. C# also has a use of goto where switch blocks cannot fall through cases, that have statements, without an explicit goto statement to go to the next labeled case. It makes missing a break; statement accidentally not possible.

Anyway, obviously a ton of languages out there, so curious which one?

1

Milnoc t1_iybpcua wrote

C/C++. But as I've said, I use them very sparingly to kick the process out of a nested loop or switch block into a general maintenance chunk of code. I would never use it to jump around within a loop or switch block.

1

xzt123 t1_iybr5of wrote

There's appropriate uses of goto, in C/C++ with nested loops and performance matters, sounds like a reasonable use.

1

davtruss t1_iycey4v wrote

I'm pretty sure if the ancient Minoans had enjoyed the ELI5 subreddit, Linear A would have been cracked long ago.

Excellent top comments so far.

0

Kulpas t1_iycfb2x wrote

As a side note: goto is often used in code golfing (the act of trying to write a piece of code in as small amount of characters as possible) because well, it's shorter than writing 'while(1)' for example.

In the case of PICO-8 (and by extension Lua) it's the difference between "::x:: do stuff goto x" and" while 1 do do stuff end" which is 2 characters longer

0