Live data from Hacker News

GOTOphobia considered harmful in C

blog.joren.ga

71–80 of 319 posts

Re: GOTOphobia considered harmful in C

#71
post #65

This blogpost is horrible! The title is good, you can tell if someone actually uses C at a decent level based off of if they describe SESE(single exit single entry) and how you use goto's to achieve that. BUT, the fact they have multiple goto locations in one function violates this! Only one goto locations ! That goto is goto cleanup, or goto exit. What you do is then check state of each variable you cleanup. Every f…

Would you say that the Linux kernel is written by mostly "100% subpar C programmers"? Because it's an extremely common pattern to have multiple goto labels at the end of a function.

Re: GOTOphobia considered harmful in C

#72
post #46

This is fun! The C version; int foo(int v) { // ... int something = 0; switch (v) { case FIRST_CASE: something = 2; goto common1; case SECOND_CASE: something = 7; goto common1; case THIRD_CASE: something = 9; goto common1; common1: /* code common to FIRST, SECOND and THIRD cases */ break; case FOURTH_CASE: something = 10; goto common2; case FIFTH_CASE: something = 42; goto common2; common2: /* code common to FOURTH a…

> The nested functions usually get inlined by the compiler, so there is no cost to them. This kind of code typically gets written when ‘usually’ isn’t good enough (of course, once you use a compiler, in theory, there are no guarantees; the compiler could compile the inlined-function one with a goto or vice versa, but programmers typically are more concerned about what happens in practice) The inlined functions also m…

I agree that programmers care more about what actually happens (and they should, when performance matters!), but this kind of analysis also involves future changes to the compiler unless it's a one-time job. Which sometimes exists, so check the assembly there and do whatever you need.

Straightforward and limited-scope code like nested functions tends to improve in performance over time, because it restricts possibilities better than goto. And it's more error-resistant to future changes for similar reasons. If your code has to last a while, you're probably better off having the safer one. Or maintain both, and use the safer one to validate the unsafe one, and choose based on benchmarks of the week - what was true when it was written could change with any version.

Re: GOTOphobia considered harmful in C

#73
post #71
post #65

This blogpost is horrible! The title is good, you can tell if someone actually uses C at a decent level based off of if they describe SESE(single exit single entry) and how you use goto's to achieve that. BUT, the fact they have multiple goto locations in one function violates this! Only one goto locations ! That goto is goto cleanup, or goto exit. What you do is then check state of each variable you cleanup. Every f…

Would you say that the Linux kernel is written by mostly "100% subpar C programmers"? Because it's an extremely common pattern to have multiple goto labels at the end of a function.

Yes. There's a reason pretty much every secure C coding standard dictates exact what I said, like CERT C etc. There's a reason they have weird bugs. Just because it's an impressive piece of software, doesn't mean it can't have horrible design pattern written by substandard coders. And in an open source project with as many contributors as Linux, I would say it's not hard to fathom that there's a significant number of substandard people writing code on that codebase. Even MISRA quoted in the article I believe intends that you only have one goto location.

For a big example of substandard coding, see this thread for an egregious wireguard module in BSD. Countless other examples. https://news.ycombinator.com/item?id=33381949

Re: GOTOphobia considered harmful in C

#74
post #66

Earlier quoted context omitted.

You can, and your program will call std::terminate if there’s already an exception being processed. Not exactly desirable if you’re trying to write code that ensures careful resource cleanup. Also why it’s widely regarded as _wrong_ to ever throw in a destructor.

IMO this is a design bug in C++. The authors couldn't agree on what to do in the exception-during-unwind scenario, so they chose the worst possible option: crash. In most cases, an second exception raised while another exception is already being thrown is merely a side-effect of the first exception, and can probably safely be ignored. If the idea of throwing away a secondary exception makes you uncomfortable, then an…

Something like std::nested_exception [0]?

[0] https://en.cppreference.com/w/cpp/error/nested_exception

Re: GOTOphobia considered harmful in C

#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"?

Re: GOTOphobia considered harmful in C

#76
post #26

> On the other hand, today we have the very opposite situation: programmers not using goto when it's appropriate and abusing other constructs, what ironically makes code only less readable. One I see all the time from beginners is creating a finite state machine using one method per state and jumping between states by calling the next state’s method from within the current state’s method. Essentially just emulating g…

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.

Re: GOTOphobia considered harmful in C

#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 because the paper is so short, assumes you know about this context, and has no concrete examples. People quite reasonably assume it's about ugly code they've encountered, but it's actually about ugly code of a completely different kind.

I'm not that old, but I was unlucky enough to have programmed in an unstructured language where GOTO was the only way to use faux-subroutines in my teens. Whatever you think as code that's difficult to follow: it's nothing compared to this.

Re: GOTOphobia considered harmful in C

#78
post #47

Earlier quoted context omitted.

I have a distaste for all of these examples, which comes from the existence of a side-effecting operation: calling do_something() necessitates the need to call a cleanup function, which means there's some state being changed but hidden behind the internals of these methods. It is really easy to call this incorrectly which says to me it's just a badly-designed API. In C# the idiomatic way would be to have each of thes…

In C# it's customary just to wave away the worst kinds of problem that C and D developers try to handle, and let the runtime kill your program. (This is more an artifact of why people pick their languages than anything inherent on the languages themselves.) But rest assured, your C# code is full of global state hidden on its runtime and is subject to the same kinds of errors people are discussing here.

"hidden on its runtime" keeps it out of the rest of thr program.

Re: GOTOphobia considered harmful in C

#79

The C version: int* foo(int bar) { int* return_value = NULL; if (!do_something(bar)) goto error_1; if (!init_stuff(bar)) goto error_2; if (!prepare_stuff(bar)) goto error_3; return_value = do_the_thing(bar); error_3: cleanup_3(); error_2: cleanup_2(); error_1: cleanup_1(); return return_value; } The D version: int* foo(int bar) { scope(exit) cleanup1(); if (!do_something(bar)) return null; scope(exit) cleanup2(); if…

Plain C version with attribute((__cleanup)): int* foo(int bar) { int* return_value = NULL; __cleanup__((cleanup_1)) int c1 = 0; if (!do_something(bar)) return NULL; __cleanup__((cleanup_2)) int c2 = 0; if (!init_stuff(bar)) return NULL; __cleanup__((cleanup_3)) int c3 = 0; if (!prepare_stuff(bar)) return NULL; return_value = do_the_thing(bar); return return_value; }

That's GCC, not standard C, right?

Re: GOTOphobia considered harmful in C

#80
post #74
post #66

Earlier quoted context omitted.

IMO this is a design bug in C++. The authors couldn't agree on what to do in the exception-during-unwind scenario, so they chose the worst possible option: crash. In most cases, an second exception raised while another exception is already being thrown is merely a side-effect of the first exception, and can probably safely be ignored. If the idea of throwing away a secondary exception makes you uncomfortable, then an…

Something like std::nested_exception [0]? [0] https://en.cppreference.com/w/cpp/error/nested_exception

Sort of, but nested_exception covers a different scenario. With nested_exception, the "attachment" is an exception which caused the exception it is attached to. In the scenario I'm talking about, the "attachment" is an exception which was caused by the exception it is attached to.

Anyway, the key missing thing is not so much the exception representation, but the ability to have custom handling of what to do when an exception is thrown during unwind. Today, it goes straight to std::terminate(). You can customize the terminate handler, but it is required to end the process.

Post reply on HN