I've recently been taking a C course as part of a university degree. We have been forbidden from using goto
, break
and continue
, and must only use a single return
statement from a function.
I have been writing C for many years as a hobby without these restrictions and have been struggling to write in the style they require - often ending up with mountains of nested if
statements. I try to avoid goto
where possible, but have a habit of using break
, continue
and multiple return
statements very liberally and have never had any issues.
Why are these features considered bad practice?
This is highly subjective, as all 4 of those things have trade-offs--pros and cons.
Ask your teacher, and report back here.
goto
has an unnecessarily bad reputation. People fear it waaay more than they should! I think it is because using goto
can be easily abused, especially if you jump outside your function, or jump backwards (upwards in the code). If you jump only downwards, however, and within the same function, not crossing over variable declarations in the process, goto
can be an excellent technique to help you achieve a clean single return
statement at the end of a function. In C, it can be the perfect way to handle errors in complex initializations! See my usage in my answer here: Opaque C structs: various ways to declare them. See also the Additional reading and justification for valid usage of goto in error handling for professional code section at the bottom of my answer there.
In some organizations, including some safety-critical embedded microcontroller applications I have worked in in the self-driving car industry, using goto
can even be required. I've worked in code bases where the above error handling technique with a single return
and using goto
was required by my organization's coding guidelines. It's not automatically evil. Rather, it's a tradeoff with pros and cons. Unfortunately, many people I've worked with also have an unfounded revulsion towards goto
which was probably planted by their teacher, like your teacher for instance. This revulsion can lead to some pretty awful code at times when goto
would have beautified and simplified it tremendously.
Note also that in C++ there are other ways to do error handling that aren't as accessible in C, but still, goto
could be used.
break
and continue
are much less-easily abused. Perhaps the only real argument against them is code clarity.
Ex: do something 10 times:
// fine, but perhaps not as clear
const int NUM_TIMES = 10;
int i = 0;
while (true)
{
printf("i = %i\n", i);
i++;
if (i >= NUM_TIMES)
{
break;
}
}
// clearer (withOUT `break`)
int i = 0;
while (i < NUM_TIMES)
{
printf("i = %i\n", i);
i++
}
// or
for (int i = 0; i < NUM_TIMES; i++)
{
printf("i = %i\n", i);
}
// The above example is trivial, but imagine you are NOT just
// incrementing a number! The non-`break` while loop with your
// condition up-front can be clearer. The `break` option is just
// fine too, but it's a matter of taste.
A single return
statement is best achieved when using goto
. Otherwise, it requires tons of nesting. So, that is contrary to your teacher's guidance, it seems.
Many people, however, opt for multiple return
statements to exit a function early and avoid tons of nested braces. It's basically a tradeoff of:
goto
, and a single return
, ORreturn
sIn languages like C, I use goto
and a single return
, unless my stinking peers won't approve it, and they fight with me, in which case I conform to whoever is reviewing me so I can get my stinking code merged. :) (Replace "stinking" with "beloved", for your peers, of course).
In languages like C++, where developers hate goto
even more than in C, I generally use multiple returns or extra nesting and breaking the code out into sub-functions--again, to appease my peers who don't know and love C.
In Python, where goto
does not exist, I use multiple returns.
At the end of the day, ask your teacher. Take mental notes. Learn why they are doing it. Learn from us. Learn from books. Form your own opinions. Begin recognizing trends and "best practices", and form your own opinions. If you need to do what your teacher wants, even if they're wrong, for the grade, do it. But do it the "better" way you determine outside that class.
In code reviews, if your stinking peer won't approve your beautiful goto
usage, try to convince them. If you can't, make the change to avoid goto
, reduce friction, and move on. It's not worth fighting about. Everything is a tradeoff. There are many "right" ways to do things.
Note to all: I say "stinking" in jest. I am very grateful for the job that I have.
Try forcing goto
to jump outside the function, even if it produces undefined behavior, as a demo to prove it is dumb: