Live data from Hacker News

GOTOphobia considered harmful in C

blog.joren.ga

91–100 of 319 posts

Re: GOTOphobia considered harmful in C

#91

In RAII languages[0], you obviously don't need unrestricted gotos. However, I always find myself missing it when writing nested loops. Labeled break and continue[1] ought to be considered standard structure programming primitives. These are restricted gotos and allowing them to break or continue a parent loop doesn't unrestrict them much. But it does significantly improve the expressive power of your looping construc…

Even with RAII in C++, goto is still useful for handling the occasional error case where you need to reset/retry some operation e.g. due to transient hardware issues that are not unrecoverable errors. A common example that comes to mind immediately is asynchronous disk reads where the data was corrupted during transfer but may succeed if transparently cleaned up and re-issued.

I use goto rarely. But there are times when anything else would be inelegant, and in those instances I'll use it without hesitation.

Re: GOTOphobia considered harmful in C

#92

In RAII languages[0], you obviously don't need unrestricted gotos. However, I always find myself missing it when writing nested loops. Labeled break and continue[1] ought to be considered standard structure programming primitives. These are restricted gotos and allowing them to break or continue a parent loop doesn't unrestrict them much. But it does significantly improve the expressive power of your looping construc…

This is one of those half-true claims that C++ aficionados make, probably because they can play a bit fast and loose with resource cleanup in their particular situations. RAII simplifies some of the resource cleanup, but at a cost: if the resource cleanup fails, there’s essentially no way to convey this. So yes, you can write a destructor that tries to clean up your resources regardless of how the code exits its curr…

> RAII simplifies some of the resource cleanup, but at a cost: if the resource cleanup fails, there’s essentially no way to convey this.

RAII at least provides a decent default. After all, most resource cleanup cannot fail, or you cannot do much other than print an error. Now, if you need to catch errors during a particular cleanup, you can still do it manually, but RAII lets you focus on these few cases.

Re: GOTOphobia considered harmful in C

#93
post #75

I'm browsing this, and I'm not seeing the way I do it, which is sort-of-like #5 but not quite... I tend to wrap the code that has multiple exits-to-label in a do...while(0) loop, and use break to get there... So it might look like: do { if (false == call_func1()) { cleanup_any_state(); break; } if (false == call_func2()) { cleanup_any_state(); break; } } while (0); At any point you can branch to the common exit-state…

At this point couldn't you just write an actual function and use "return"?

So the sort of stuff I've been using this in is encryption/decryption, where there's a whole boatload of things you have to set up, read/create OIDs, configure identities, fetch certificates, match algorithms, etc. etc.

All of that has to be ok before you finally get to the bit that does the work, and since I'm using ObjC with its ARC feature, I don't need to deallocate anything, they'll be deallocated as they go out of scope. I tend to release critical RAII stuff in my -dealloc method anyway if there's anything there to be done.

So it's really a whole long list of

  id result = nil;
  do {
    if (setup-X-fails)
      break

    if (setup-Y-fails)
      break

    ...

    result = call_method(X,Y,Z,A,...F)
  } while (0);
... which works out pretty well, and is very readable. The setup-xxx stuff can be several pages of code for each method - and useful in their own right, so integrating it into the loop doesn't seem preferable.

Re: GOTOphobia considered harmful in C

#95
post #86
post #77

Earlier quoted context omitted.

The thing is that many people today have never encountered the sort of spaghetti code that Dijkstra was talking about in 1968. There's plenty of confusing and messy code around, but true spaghetti code that GOTOs all over the place and is nigh-impossible to follow has been extremely rare for a long time. I can't recall encountering it in the last 30 years. It easy to misunderstand what he was even talking about becau…

This. To find an example, I did a search for “Commodore PET Basic programs”. Here’s a book from 1979 that shows what spaghetti code looks like, in my opinion: http://www.1000bit.it/support/manuali/commodore/32_BASIC_Pro... The first program listing is on page 24 of the PDF. Try to follow the logic of the program. Why does line 400 go to 280? What paths can lead to line 400? Who knows! And this is high-quality BASIC b…

Wow, that takes me back. I learned to program on a PET and would have devoured this book had it been available. As it was one of our math teachers was tasked with teaching the computer classes bu didn't have any programming knowledge beyond input/output, loops, and simple calculations. Books and manuals were hard to come by.

Re: GOTOphobia considered harmful in C

#96
post #84
post #77

Earlier quoted context omitted.

The thing is that many people today have never encountered the sort of spaghetti code that Dijkstra was talking about in 1968. There's plenty of confusing and messy code around, but true spaghetti code that GOTOs all over the place and is nigh-impossible to follow has been extremely rare for a long time. I can't recall encountering it in the last 30 years. It easy to misunderstand what he was even talking about becau…

Do you know of a good example you could link?

I dug around a little and found an example [1] on a reddit thread looking for examples of spaghetti code. Most of the examples on the thread were just badly written code. Irreducible spaghetti code tends to be complex state machines that cannot be rendered well in a flat format. People like to flatten those out with a trampoline pattern[2], but that can hinder performance.

Malicious spaghetti involves transformations such as

   for (x = 0; x 
[1] http://wigfield.org/RND_HAR.BAS

[2] https://en.wikipedia.org/wiki/Trampoline_(computing)

Re: GOTOphobia considered harmful in C

#97
post #77
post #50

I always encourage people to go read Dijkstra's GOTO paper, instead of just its title. It's a short and easy read, almost like a blog post. If you pay attention, you can see that the he was talking about spaghetti code vs structured code. It's better when the lexical structure of the source code maps to the execution structure. That is, if you know what is the current line being executed, you have a good idea of what…

The thing is that many people today have never encountered the sort of spaghetti code that Dijkstra was talking about in 1968. There's plenty of confusing and messy code around, but true spaghetti code that GOTOs all over the place and is nigh-impossible to follow has been extremely rare for a long time. I can't recall encountering it in the last 30 years. It easy to misunderstand what he was even talking about becau…

> The thing is that many people today have never encountered the sort of spaghetti code that Dijkstra was talking about in 1968.

Can't highlight this enough. The type of spaghetti code "goto considered harmful" was reacting to is basically impossible to create anymore, so anyone who didn't work on that type of code in the 80s or earlier probably hasn't seen it.

And thus, is applying the mantra "goto considered harmful" incorrectly. (Such as trying to avoid it in C for clean error handling, when there's no reason to avoid that.)

To try to replicate that experience, you'd have to write your entire application (including all libraries since libraries were often not a thing) as one single function in C. All of it, no matter how many tens of thousands of lines of code, all in one function. Then label every line. Then picture having GOTOs going every which way to any of the labels. For instance you'd preset the counter variable to some desired value and jump right into the middle of a loop elsewhere. Over time you'd surely accumulate special conditions within that loop to jump out. And so on. It's difficult to even imagine code like this today (or in the past 30 years).

Re: GOTOphobia considered harmful in C

#98
post #24

Earlier quoted context omitted.

Go doesn't have RAII or destructors, it has defer.

defer proposal for C made in 2021 https://www.open-std.org/jtc1/sc22/wg14/www/docs/n2895.htm ... why isn't this in C already?

You must be new here. They’ll consider adding it in late-mid-‘40s.

Re: GOTOphobia considered harmful in C

#99

In RAII languages[0], you obviously don't need unrestricted gotos. However, I always find myself missing it when writing nested loops. Labeled break and continue[1] ought to be considered standard structure programming primitives. These are restricted gotos and allowing them to break or continue a parent loop doesn't unrestrict them much. But it does significantly improve the expressive power of your looping construc…

This is one of those half-true claims that C++ aficionados make, probably because they can play a bit fast and loose with resource cleanup in their particular situations. RAII simplifies some of the resource cleanup, but at a cost: if the resource cleanup fails, there’s essentially no way to convey this. So yes, you can write a destructor that tries to clean up your resources regardless of how the code exits its curr…

If you need fallible cleanup, but also to try cleanup via RAII, it isn't hard to have a "cleanup" method that signals whether it succeeded, and an "already cleaned up" boolean member the destructor checks.

Re: GOTOphobia considered harmful in C

#100
post #76

Earlier quoted context omitted.

This is one of those problems that Tail Call Elimination cleanly addresses. The "obvious" approach to writing an FSM does exactly what you'd expect.

C does not guarantee tail call elimination. But you can do the same with an event loop that cleanly avoids goto.

Nowadays you can direct clang to require tail-call elimination in C. [1] In gcc you can provide the optimization flag, -foptimize-sibling-calls, which is automatically selected at -O2, -O3, or -Os. [2]

[1] https://clang.llvm.org/docs/AttributeReference.html#musttail

[2] https://gcc.gnu.org/onlinedocs/gcc/Optimize-Options.html

Post reply on HN