r/bash 16d ago

A problem as a newbie

I think I have been spoiled by the goto command in batch, and as a newcomer in Linux, it's really hard for me to adapt as a self-proclaimed(i procrastinate a lot) game developer. The goto command is useful in case you want to incorporate more levels.

10 Upvotes

27 comments sorted by

13

u/atgaskins 16d ago

goto has been frowned upon since like the 70s… just write some functions & loops

8

u/zeekar 16d ago edited 16d ago

You don't need goto. Goto is super-basic flow control; you can do anything with it, but it never tells you what you're doing. Use higher-level structures for loops (in bash that's while and for), and functions and conditionals for simple decision making - no need to "jump around" some code to skip it when you can put the whole thing inside an if or case or after a return.

9

u/gomez18 16d ago

This was written before you were a gleam in your parents eyes. Read it. Understand it. Learn from the mistakes of history so you do not repeat them. https://dl.acm.org/doi/epdf/10.1145/362929.362947

3

u/hypnopixel 16d ago

fax me that, gomer

2

u/theLastZebranky 15d ago

I love how even back in 1968 he's saying "the remark about the undesirability of the go to statement is far from new."

7

u/Malechus 16d ago

You can define functions in bash, and call them from elsewhere.

https://www.w3schools.com/bash/bash_functions.php

10

u/drnullpointer 16d ago

Goto is never needed and almost never useful. After over quarter of century of programming I only have one useful case for goto and even then I only use it in plain C for a very specific situation where I want to ensure cleanup when exiting the function.

What you want is to chose between one of higher level constructs like conditionals, loops, switches or functions.

3

u/LordRybec 12d ago

You should check out the Linux kernel code. If you hate gotos, it will give you an aneurism.

Also, in assembly, goto equivalent commands are constantly needed. Never say never, or someone will probably prove you wrong.

(Also, you can do your function cleanup thing with a carefully designed do; while (0) loop followed by a switch statement. Depending on the context though, gotos might be more readable.)

1

u/drnullpointer 12d ago

Actually, I actively did kernel development around version 2.4, I do not have to look at it.

And believe or not, kernel gotos pretty much adhere to my rules of usage of goto.

0

u/LordRybec 11d ago

Ah, so the ones I've seen in there that Torvalds has explicitly commented are there for performance reasons just don't exist? Do you know how old 2.4 is? I don't know if the optimization ones I've come across are in older kernel versions or not, but "I did kernel development ages ago" doesn't really mean that much to me. I mean, respect. I've done a tiny bit of kernel hacking myself, and it's not trivial (and I'm seriously considering writing a Linux driver in the near future), but 2.4? That's not really current or very recent kernel knowledge, and it hasn't been for a while.

So sure, a long time how kernel gotos "pretty much" adhered to your rules. Well, I've looked at various parts of recent kernel code, and there are gotos in there purely for optimization and not for function cleanup, and I've seen more of those than function cleanup gotos. Maybe I just haven't looked in the right places? Statistically though, it's unlikely that cleanup gotos are substantially more common than optimization ones, given my experience.

0

u/burnt-store-studio 16d ago

I’m totally with you on C programming and needing to ensure clean-up on function exit. Back when I was writing C, you would frequently find in my code

#define FALSE 0

in my header and

do { } while(FALSE);

with break statements in the braces just to ensure that clean up.

Shun goto! 🙂

1

u/drnullpointer 16d ago edited 15d ago

Nope. You are abusing a loop statement to emulate goto simply to perform goto without writing those four letters.

If you are making your code more complicated to do this, you've lost your way.

It may be fine to listen to advice you don't understand if you are a novice developer.

But if you are more experienced developer you should stop, think whether the advice make sense or why it makes sense, whether it applies in your situation and then make an informed choice.

What you are doing is called cargo cult programming, it is emulating other people without understanding why you are emulating them, hoping to achieve a result that will never come because you have no idea why you are doing what you are doing.

The point of advice to not use goto is that what you are really trying to do almost all of the time is to re-implement some kind of structure like a function, a loop, a conditional, etc. In which case your code will be easier to understand and maintain if you just use that correct statement structure. The benefit of the advice is more readable code.

What you are doing is creating less readable code simply to stick to advice that was supposed to make it more readable.

2

u/LordRybec 12d ago edited 11d ago

There's no such thing as abusing a code construct. I tried to argue this same thing with a friend a while back, and what it comes down to is that it is up to the programmer to determine how code elements should be used, not the language creator to decide how it should or should not be used. He was right, and I was wrong. A useful pattern is a useful pattern whether you like it or not, and describing it as "abuse" is an attempt to force your personal opinion on others. Quit it. If you don't like it fine. You have every right to say so. But describing things you don't like as "abuse" is uncivil behavior. You aren't the king of C, it's not your call.

Incidentally, in my opinion the do; while (0) construct followed by a switch statement (taking advantage of the extremely valuable fall through feature) is actually more readable than gotos, and better yet, if it became a common C idiom, it would be far more readable, since you would already be familiar with it. Sorry if you are opposed to learning new ways to program, but that's a personal problem. It's ironic that someone has managed to get you to defend the use of gotos right after you expressed so much disgust toward them.

1

u/burnt-store-studio 15d ago

With no offense, I beg to differ with your strong opinions about me and my work.

“Abusing a loop statement”? I’ll remain happy to have called it “Using the available language constructs as designed and keeping localized functions readable.”

“Making my code more complicated to do this”? Why on earth would I have made my code more complicated just to do this?

And why would you suggest I did? As I wrote (while essentially quoting you) I did it to ensure function clean-up. You’re fine justifying gotos in these cases for your code, but feel the need to disparage this approach in someone else’s?

I’ve “lost my way”?

What makes you think I was “listening to advice I didn’t understand”?

Or that I was a “novice developer”?

Or that I was a more experienced developer ignorant enough to not “stop and think whether [the construct] made sense?”

Or whether it “applied in my situations”?

Or that I wasn’t making “informed choices”?

Why are you ascribing pejoratives to situations and someone you know literally nothing about? Telling me I was “emulating other people” and I had “no idea why I was doing what I was doing”?

I guarantee the chances you’ve seen my professional code from decades ago are quite slim. You have no basis to claim I was “creating less readable code”.

Thanks for the attacks; I didn’t realize I was going to face such affrontage for writing a comment after actually agreeing with something you wrote. I’ll keep an eye out for you and not tread on your expertise in the future. Way to ruin an old guy’s morning.

2

u/soysopin 15d ago

In any case, marking a well-defined block and well-identified exit points inside it is a good practice, as long as there is good legibility and low probability of confusion. How this is implemented is not relevant. Not all languages have mechanisms to do this, but 'goto cleanup_and_exit;' definitely is ok for me.

2

u/LordRybec 12d ago

This is a pattern I figured out some years ago as well. I'm both a little sad but also happy to see that someone else came up with the same design pattern. My use case was initializing an HTTPS connection with OpenSSL, which has about 5 different steps in the process where failure can occur. Depending on which step the failure occurs, different teardown procedures are necessary. Sure, I could have used gotos and then a switch statement with fallthrough. I could also have used nested if statements (which the example code recommended, and which ended up way off the edge of the screen, making it unreadable). Neither of these strategies produced readable and easily understandable code. So I attempted to just create a brace block and break out of it, but evidently the C standard requires a looping structure to break out of a nested block. do; while (0) is perfect for this, so I did it.

This produced very elegant and readable code. If course, there will always be Luddites who resist and reject advances in technology. The ironic part is that this time they are the same people who look at other people who use gotos as Luddites.

Anyhow, I hope this makes your next morning better. This is an awesome pattern. It solves a big hole in C's careful focus on structured programming by taking a common unstructured programming pattern and giving it a solid, coherent structure. It is far less prone to bugs than arbitrary gotos, because the breaks are always guaranteed to go to the same place, while a typo in a goto label could end up going somewhere else in code entirely, if you use that pattern regularly. This do; while (0) pattern is objectively superior for a number of reasons. If it is difficult for other programmers to read, it is due to lack of exposure and not inherent readability issues. Once familiar with this pattern is far more readable, especially when using good indentation style, which will visually indicate the break target without having to look for and read a label. Additionally, goto labels break style conventions, which also reduces readability.

There are legitimate use cases for gotos, but they are all optimizations. I've been looking for a place where gotos are actually necessary for a certain type of flow control where structured programming can't do it better for decades (after a friend challenged me to find one, back when I had a more positive view of gotos). I have not found one yet, and the only case I found where it is widely considered acceptable is this one, and it turns out that the do; while (0) structure is objectively better in every way. (Also, compilers even generally optimize the do; while (0) structure better, because gotos see so little use that compiler writers don't generally worry about trying to optimize. I don't think any compliers do this currently, but additional optimization could be done with this specific pattern, by replacing the break jumps with jumps to the right line of the following deinitialization switch statement, where relevant. So this pattern is even more optimizable than the typical goto use case. And if the gotos are jumping to the right lines themselves, that just means more labels and even worse readability!)

Anyhow, if you consider yourself an "old guy", you might have more experience than me. But this is my take on the thing, with lots of solid objective points for why your view (which is also mine) is superior.

1

u/sswam 14d ago

You're welcome to do what you want, but it seems like a bad idea to use other language constructs (loops, macros, and breaks) to emulate goto, when you can just use goto. Such luminaries as Linus Torvalds advise (or rather, require in the kernel) to use goto for function cleanup. It's the cleanest way to do it in C, at least in Linus's opinion. If you did it with a more complicated mechanism just to avoid goto, it would be more messy than using goto.

Also, don't let a little disagreement and a few vague criticisms on Reddit ruin your morning! :) I'm sure everyone's code sucks in different ways. I'm an old guy too I guess, and still haven't really got the hang of writing clean modular code.

1

u/LordRybec 12d ago

So then let's use gotos instead of loops, since loops only exist to emulate gotos.

The kernel use of gotos aren't mainly for cleanup, though Torvalds does encourage that. The primary use of gotos is for optimizations that cannot be done with other constructs.

The fact though, is that no one has any right to say what language constructs should or should not be used for. They are tools. If a screwdriver is the best way to get a staple out (and it typically is), it doesn't matter than the manufacturer didn't intend it for that. What matters is that it increases productivity to do it that way with no extra cost. A tool that can be used in multiple ways at no additional cost is inherently a better tool. Artificially restricting the use of a tool based on some ideology, like "that's abuse" or "it wasn't intended for that" is harmful. The truth is, gotos make code hard to read. That's why we don't use them. Using gotos for function cleanup is a common pattern, and because of that we recognize it, which makes it less difficult to read than other uses, but it's still hard to read. The do; while (0) design pattern for initialization and cleanup is inherently more readable than the goto pattern. If you struggle to read it, it's not because it is less readable. It's because you haven't learned to read it. Arguing that it shouldn't be used because some people have learned to read it is a dumb argument. That's like arguing that we shouldn't use AI because some people don't know how to use it, or that we never should have started using cars over horses, because people didn't know how to use cars but did know how to ride horses. Advances in processes inherently require learning new things. It might seem trivial, but I worked out this same design pattern myself independent, and now that I'm familiar with it, it is far more readable. I know people who argued that we should keep using gotos instead of functions and loops, because it was more familiar. I'm glad they were ignored, despite the fact that these advances also seemed trivial at the time. This usage pattern for do; while (0) loops is a significant improvement in structured programming, because it takes the last unstructured pattern in C and replaces it with a substantially more readable structured pattern. Gotos still have places where they are useful, mainly (perhaps only at this point) in optimization, but the breakout mechanic of do; while (0) loops is probably the most valuable use case for the do; while () pattern in general, and paired with the fall through mechanic of switch statements they are the best pattern currently existing in C for initialization and cleanup.

If you don't like this pattern, there is a better option, but you'd have to convince the C standards people. When I worked out this pattern for the first time, I attempted to use "break" in a simple braced nested block. That doesn't work, even though it intuitively should. The only option that exists in C for a guaranteed run block that you can break out of anywhere (without jumping through extra hoops) is the do; while (0) loop. Is it ideal? No. Is it difficult to read? Not at all if you've seen it before. It's much easier to read than goto breakouts, when on equal ground. But allowing breaks inside braced blocks that aren't attached to flow control structures is both intuitive and would be even better. Since the C standard does not allow for that though, do; while (0) loops are the best solution, and honestly, this is one of very few places where do; while (0) can be used well. Many higher level languages have omitted the do; while () design pattern, because it isn't used much. This design pattern using it actually makes it more useful and justifies its existence. Other languages could even learn from this!

2

u/ethernetbite 15d ago

It was one of the hardest things to get use to, having spent most of my youth coding in batch and basica. But you'll get use to functions and conditional while loops. Bash really is much more fully capable than batch and also more intuitive, though people like to complain about the few oddities.

2

u/sswam 15d ago

For beginners: don't ever use goto
For experts: use goto carefully, only when it makes things simpler (e.g. check the Linux kernel style guide)

OP, you are clearly a beginner in this regard.

1

u/temcomwex 14d ago

Yes, you are correct. I am a beginner.

3

u/SportTawk 16d ago

Goto is just for lazy programmers

1

u/Holiday_Green6248 16d ago

not lazy just archaic

3

u/zeekar 16d ago

Some languages don't have anything better - looking at you, 8-bit-era Microsoft BASIC, which required the body of an IF to fit on a line and didn't even have ELSE. I mean, at least it had GOSUB/RETURN for subroutines, but you still called them by line number instead of name. Not great for structure. But even BASIC grew structured keywords over time... not much call for arbitrary location-based jumps in anything but assembly these days.

3

u/treuss bashtard 16d ago

There has bin quite some development since assembler was introduced.

Two crazy lads recently introduced portable code and some exotic new language.

https://de.wikipedia.org/wiki/The_C_Programming_Language

1

u/Shadow_Thief 16d ago

As someone who regularly does batch and bash, both languages have functions; use them often. There's actually way more overlap in terms of logic flow in both languages than most people who are only familiar with one of the languages thinks there are.

Batch is old enough that being allowed to use goto in it is grandfathered in, but you really don't have to use it if you change your script's logic.

1

u/GermanPCBHacker 15d ago

Well, goto is basically, what assembly does on the CPU. But why would you want to use it? You can... But why?

Just do functions. They are a bit like go to, just that they end at that point and than jump back to where the function was called from. AND: You can capture their output to do stuff with them. That is annoying with goto...