Hacker News new | ask | show | jobs
by quietbritishjim 23 days ago
> > 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.

1 comments

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.