Hacker News new | ask | show | jobs
by lionkor 22 days ago
RE the article you've linked:

> everyone knows goto was bad.

Absolutely hard disagree. You can write extremely clean and resilient C with C89, goto, and a handful of rules. Telling people `goto` is bad is how we get shitty C programs and paradigms where goto would have been better.

Goto isn't bad, its misuse is bad. Beginners will write shit code regardless of whether you tell them they can or can't use goto. That's also exactly what Dijkstra was arguing, if you read past the much misquoted "goto considered harmful", which he never said (it was an editorialized title, and not even the full version).

3 comments

> > everyone knows goto was bad.

> Absolutely hard disagree. You can write extremely clean and resilient C with C89, goto, and a handful of rules.

That's a different goto. The one in C89 can only jump around within functions, but the article is talking about goto that can jump between any two points in the whole codebase arbitrarily. It stresses that point a bit more later on in the article, but you can already see it from the FLOW-MATIC code quoted above (which doesn't even have functions).

Your point actually still stands: it's theoretically possible to write clean code using even the more general goto. (Probably by building abstractions with it like "function" and "for loop".) But would you be happy doing that with someone else - or especially with a coding agent? It's better that the "handful of rules" are enforced by the language, in my opinion.

---

Edit:

> That's also exactly what Dijkstra was arguing, if you read past the much misquoted "goto considered harmful", which he never said

I just re-read the original "GOTO considered harmful" article (it's short and clear) and, while the title might not have been his, Dijkstra was definitely making a very plain argument that goto is bad for everyone and should be scrapped. He says in the introduction:

> I [have] become convinced that the go to statement should be abolished from all "higher level" programming languages (i.e. everything except, perhaps, plain machine code).

And in the conclusion:

> The go to statement as it stands is just too primitive; it is too much an invitation to make a mess of one's program.

Here is a structured cross-codebase GOTO for C++, with optional declared & typed continuation values, sub-tasks/states/state-machines, and optional delegated typed termination values.

  // Syntax: { ...; y = go_to state1(x, ...); }
  // Meaning: Cross-codebase GOTO w/continuation values
  // Implementation: tail call
  #DEFINE go_to return

  // Syntax: { ... y = go_do state2(x, ...); ... }
  // Meaning: Cross-codebase sub-task/sub-state
  // Implementation: normal call
  #DEFINE go_do

  // Syntax: { ... go_terminate(y); }
  // Meaning: State machine termination
  // Implementation: normal return
  #DEFINE go_terminate return

  // Syntax: int state3 state(int x, ...) { ... }
  // Meaning: Structured state definition
  // Implementation: normal function
  #DEFINE state

  // SYNTAX: if (GOTO_NOT_HARMFUL) { ... };
  // Meaning: GOTO is now cleaned up
  // Derivation: Achieved
  #DEFINE GOTO_NOT_HARMFUL true
Example:

  int state1      state() { ...; go_to state2(m); }
  int state2 state(int m) { ...; y = go_do substate2a(); go_to state3(); }
  int substate2a  state() { ... ; go_to substate2b(q); }
  int substate2b  state() { ... ; go_terminate(q); }
  int state3      state() { ...; switch (...) { case 1: go_to state4(v); case 2: go_to state5(); ...} }
  int state4 state(int v) { ...; go_terminate(r); }
  int state5      state() { ...; go_to state3(); } // State cycle
So now you can have your #include <go_to>

EDIT: Compressed/cleaned up my mess

That's not the same: you have to cooperate in the game, so if you have a library that uses it internally and you call one of its functions in the normal way then it will still just return as usual. So it still provides the usual guarantees of function calling, even if you don't want it to.

(It also doesn't allow you to jump into the middle of a function, or to take more than a finite number of steps unless you're using a compiler with guaranteed tail call elimination.)

Just to add:

If you want to have proper jump-anywhere goto in C, you can do it a lot more simply than that: just put all your code in one function and use regular goto. If you want to use only structured programming constructions, use a while(true) loop with a switch statement inside.

The fact remains that code outside that function can still call it safely in the normal way.

I have written C code for several decades. I hate a priori, divorced from context, rules such as "never use goto". "Avoid premature optimization" as a rule is much worse. I used goto a few times in that timespan, surrounded it with rebellious comments, but largely the advice has more than weakly held for me. I don't think goto somehow liberates C developers and avails superior architectures.
Bad code is result of not following enough good practices rather than following one too many. Goto creates too much cognitive load. It had to be phased out to make room for better ideas on describing the intention with code more clearly.