Goto, Break and Continue
category: offtopic [glöplog]
The missing return is a warning, I just missed it when creating a test example. There is a definitive error though.
After case 1 there's a declaration of m, which creates an implicit scope (or whatever is that thing called). This makes jumping to case 1 equal to trying to enter that scope while bypassing initialisation of m, which is generates an error.
A possible solution to this would be to enclose the code in case 1 in curly braces. It's also a humble reminder that C/C++ switch is but a computed goto.
After case 1 there's a declaration of m, which creates an implicit scope (or whatever is that thing called). This makes jumping to case 1 equal to trying to enter that scope while bypassing initialisation of m, which is generates an error.
A possible solution to this would be to enclose the code in case 1 in curly braces. It's also a humble reminder that C/C++ switch is but a computed goto.
Quote:
Also exceptions prevent redundant code; checking a result code for an error per "if" is code executed 100% of the time for 0.0001% of the chance that an error happens. That alone gives you a clue.
I don't understand your point here.
Quote:
Plus that exception handling breaks out the error handling code out of the routine, where it does not belong.
I would argue that errors should in many if not most cases be handled where they happen instead of "somewhere else", especially if they are something that the code can reliably recover from. And if the stack unwinds far, it's even further from where it should be.
Quote:
Plus that it forces a programmer to always think about how a resource (memory, handle, transaction, connection) at initialization is always freed (see RAII), which causes always stable running code if an error happens or not.
I don't see how exceptions per se have much if any relevance to this. Sure, you can free your stuff in the catch block in your exception handler, but you can also do it manually or when handling your errors. RAII is an idiom mostly meant to solve problems that exceptions cause in the first place.
I used to think that RAII means acquiring resources in a way that you can't avoid releasing them. E.g. create an instance on stack instead of using new/delete. Stuff on stack can't avoid getting released by the time you're leaving the scope. No need to do it in the catch clause.
Quote:
RAII is an idiom mostly meant to solve problems that exceptions cause in the first place.
You are lucky you are not working for me as a programmer, because you would be out of the job quick with this attitude.
I for one am glad I'm not working in a team under Salinga, I guess.
After an exhausting research effort of nearly a minute, I found the following quote from Sir Alfred Wikipädie, the inventor of Truth:
So, Mr. C++ Tough Guy watcha say now!!
Quote:
The technique was developed for exception-safe resource management in C++[3] during 1984–89, primarily by Bjarne Stroustrup and Andrew Koenig,[4] and the term itself was coined by Stroustrup.
So, Mr. C++ Tough Guy watcha say now!!
I think I’ll live.
Agree with Preacher here.. Preach!
FYI, Jonathan Blow, the game programmer who is creating a data oriented programming language called Jai might be of interest to anyone who likes this topic.
https://www.youtube.com/user/jblow888
FYI, Jonathan Blow, the game programmer who is creating a data oriented programming language called Jai might be of interest to anyone who likes this topic.
https://www.youtube.com/user/jblow888
Quote:
I would really like to learn the reason you are asking this.
If anyone's still wondering:
I recently started A-Level computer science. My teacher has said that if you use Goto, Break or Continue in your code then you are creating bad code, and you should write it using temporary variables and flags (except of course for breaks in a switch, and possibly other edge cases). If we use any of the three above we get marked down.
A friend and I thought this weird as we had both been using break and continue in our code before, and so I thought to ask the opinions of tech professionals on the subject.
My 15 years of professional software development says this: What. The. Fuck?
Ask him if it makes a difference if you're over 40 and not a student anymore. Or if it's ok to save time by using a break or continue, if it's friday afternoon and you're getting late for a date.
Molive: That is pretty much bullshit.
A break is an early exit condition, similar to multiple return statements in a function (some people also don´t like those), and as such a pretty clean and safe construct.
Continue is a bit more arguable, but as long as your loops have a proper iteration condition it is not problematic either (and if you don´t have one avoiding a continue wouldn´t get rid of the main problem either).
Littering the code with plenty of (often badly named and not necessarily properly checked or initialized) helper variables is worse than using one of the special control flow statements which clearly tell their purpose.
Worst case would be simulating the continue/break behaviour using a continue_loop flag or a bunch of nested ifs - formally it would qualify a "good code", but actually hand-implementing something which is already built into the language is pretty dumb.
A goto is usually better to be avoided in favour of a more distinct control flow, but in some rare cases it might still be the best alternative.
Note that all of the above mainly apply to languages with a strong procedural style, those with a more functional or declarative approach usually promote different constructs which are better suited there.
A break is an early exit condition, similar to multiple return statements in a function (some people also don´t like those), and as such a pretty clean and safe construct.
Continue is a bit more arguable, but as long as your loops have a proper iteration condition it is not problematic either (and if you don´t have one avoiding a continue wouldn´t get rid of the main problem either).
Littering the code with plenty of (often badly named and not necessarily properly checked or initialized) helper variables is worse than using one of the special control flow statements which clearly tell their purpose.
Worst case would be simulating the continue/break behaviour using a continue_loop flag or a bunch of nested ifs - formally it would qualify a "good code", but actually hand-implementing something which is already built into the language is pretty dumb.
A goto is usually better to be avoided in favour of a more distinct control flow, but in some rare cases it might still be the best alternative.
Note that all of the above mainly apply to languages with a strong procedural style, those with a more functional or declarative approach usually promote different constructs which are better suited there.
@Molive: It's senseless that your teacher bans these things. Ok,. maybe goto is too taboo and most people ban it anyway, but the rest are frequently used in real jobs and at the end if one doesn't ever use them how will they ever learn when there is a good or a bad way to use them and why?
I would love to see what your teacher’s loops look like. I can imagine all sorts of horrible contraptions to go around break and continue, but not a single good one. Unless in some very fringe cases.
or his teacher's switch statements, that must be a masterpiece of ingenuity to avoid breaks there :D
Quote:
I recently started A-Level computer science. My teacher has said that if you use Goto, Break or Continue in your code then you are creating bad code, and you should write it using temporary variables and flags (except of course for breaks in a switch, and possibly other edge cases). If we use any of the three above we get marked down.
A friend and I thought this weird as we had both been using break and continue in our code before, and so I thought to ask the opinions of tech professionals on the subject.
Poor you, it's one of those teachers that (not deliberatly) try to destroy your interest/... in the subject, and making sure to corrupt others' minds so it'll be hard for them to unlearn all the things in order to be able to code properly.
I'm not exactly sure what the best approach is to this (esp. if it's too late to change courses etc.), I listened to their commands, but ridiculed them in a subtle but clear way during the exam. I passed those :D (started my 2nd year in uni now). But don't just follow advice from random people on the Internet.
Also, rule of thumb, basic programming classes always suck^[citation needed], and the advanced stuff is filled with boring formal methods^[disputed]. That's why I'm studying hardware stuff instead.
If this is A-level, I think your teacher just wants to drive home a point that gotoey stuff can be avoided. In training exercises you often go extreme and do things the weird way simply to get the hang of it.
So my opinion: bullshit from real world perspective, but a valid requirement for a class. Just play along and wait until the lessons become more advanced.
Of course unless he's a nutjob who says that you should check for printf() return value, or your code is unacceptable. I really met one like that.
So my opinion: bullshit from real world perspective, but a valid requirement for a class. Just play along and wait until the lessons become more advanced.
Of course unless he's a nutjob who says that you should check for printf() return value, or your code is unacceptable. I really met one like that.
Quote:
If anyone's still wondering:
I recently started A-Level computer science. My teacher has said that if you use Goto, Break or Continue in your code then you are creating bad code, and you should write it using temporary variables and flags (except of course for breaks in a switch, and possibly other edge cases). If we use any of the three above we get marked down.
A friend and I thought this weird as we had both been using break and continue in our code before, and so I thought to ask the opinions of tech professionals on the subject.
I was pretty sure that either this would be the case or that of a boss with specific demands in code structuring. This reminds me a bit of our professor in computer programming at our university, who was a decent fella I might add, that had demonstrated an example of case structuring using only goto and wanted us to do the same in the exams (the example could pretty well be done using the if/elseif/endif statements). When I asked him about this he told me that of course this is also a very good way to do it but to bear with him and understand that since he hadn't demonstrated, thus taught us this in the class, we were not allowed to do it with the if/else method. So I did it the goto way and passed the course. Basically it is pretty ok to use goto/continue/break statements (or any other statement) in real life and don't let anyone tell you otherwise.
Quote:
Of course unless he's a nutjob who says that you should check for printf() return value, or your code is unacceptable. I really met one like that.
I've sometimes found printf's return useful, but did you know that fclose has a return value?
I know, must be really frustrating for the ocd types. Got value, will handle.
It's always about context. Any feature of a programming language was added to that language for a reason. When a language has been around for a long time then the reasons can become irrelevant. Goto is an example of a language feature that overstayed it's welcome, but if you want to use goto in your own code which only you will ever read then go ahead. Continue and break, however, are essential features that no respectable professional frowns upon today.
Whatever gets the job done and helps you maintain tons of code which you didn't touch for a few years.
I'm not using goto, but after reading this thread I might consider actually using it for the particular case of file loaders, which basically validate stuff each second line, potentially needing to gracefully abort. this is dumb code that basically reads like script anyway.
Continue and break are useful tools for control flow - if your idea of an algorithm doesn't suck in the first place. Not a friend of "there is the single one correct way to write c++ and everything else is wrong!" mantra. I've worked on massively different projects, 15 years codebase MFC stuff. cross platform game code, nowadays audio stuff. I always found it easier to adapt to the conventions I found (be it exceptions or oldskool return value checking) than to question everything and start style debates. For audio code, performance and cache friendlyness considerations made me adapt a less defensive coding style which just wouldn't do in an enterprise context, but what the hell.
I'm not using goto, but after reading this thread I might consider actually using it for the particular case of file loaders, which basically validate stuff each second line, potentially needing to gracefully abort. this is dumb code that basically reads like script anyway.
Continue and break are useful tools for control flow - if your idea of an algorithm doesn't suck in the first place. Not a friend of "there is the single one correct way to write c++ and everything else is wrong!" mantra. I've worked on massively different projects, 15 years codebase MFC stuff. cross platform game code, nowadays audio stuff. I always found it easier to adapt to the conventions I found (be it exceptions or oldskool return value checking) than to question everything and start style debates. For audio code, performance and cache friendlyness considerations made me adapt a less defensive coding style which just wouldn't do in an enterprise context, but what the hell.
Something to fuel your nightmares, a sweet mix of goto and two nested levels of switch. Taken straight from some versions of rogue.
Code:
get_desc(obj, desc)
object *obj;
char *desc;
{
char *item_name;
struct id *id_table;
char more_info[32];
short i;
if (obj->what_is == AMULET) {
(void) strcpy(desc, "the amulet of Yendor ");
return;
}
item_name = name_of(obj);
if (obj->what_is == GOLD) {
sprintf(desc, "%d pieces of gold", obj->quantity);
return;
}
if (obj->what_is != ARMOR) {
if (obj->quantity == 1) {
(void) strcpy(desc, "a ");
} else {
sprintf(desc, "%d ", obj->quantity);
}
}
if (obj->what_is == FOOD) {
if (obj->which_kind == RATION) {
if (obj->quantity > 1) {
sprintf(desc, "%d rations of ", obj->quantity);
} else {
(void) strcpy(desc, "some ");
}
} else {
(void) strcpy(desc, "a ");
}
(void) strcat(desc, item_name);
goto ANA;
}
id_table = get_id_table(obj);
if (wizard) {
goto ID;
}
if (obj->what_is & (WEAPON | ARMOR | WAND | RING)) {
goto CHECK;
}
switch(id_table[obj->which_kind].id_status) {
case UNIDENTIFIED:
CHECK:
switch(obj->what_is) {
case SCROLL:
(void) strcat(desc, item_name);
(void) strcat(desc, "entitled: ");
(void) strcat(desc, id_table[obj->which_kind].title);
break;
case POTION:
(void) strcat(desc, id_table[obj->which_kind].title);
(void) strcat(desc, item_name);
break;
case WAND:
case RING:
if (obj->identified ||
(id_table[obj->which_kind].id_status == IDENTIFIED)) {
goto ID;
}
if (id_table[obj->which_kind].id_status == CALLED) {
goto CALL;
}
(void) strcat(desc, id_table[obj->which_kind].title);
(void) strcat(desc, item_name);
break;
case ARMOR:
if (obj->identified) {
goto ID;
}
(void) strcpy(desc, id_table[obj->which_kind].title);
break;
case WEAPON:
if (obj->identified) {
goto ID;
}
(void) strcat(desc, name_of(obj));
break;
}
break;
case CALLED:
CALL: switch(obj->what_is) {
case SCROLL:
case POTION:
case WAND:
case RING:
(void) strcat(desc, item_name);
(void) strcat(desc, "called ");
(void) strcat(desc, id_table[obj->which_kind].title);
break;
}
break;
case IDENTIFIED:
ID: switch(obj->what_is) {
case SCROLL:
case POTION:
(void) strcat(desc, item_name);
(void) strcat(desc, id_table[obj->which_kind].real);
break;
case RING:
if (wizard || obj->identified) {
if ((obj->which_kind == DEXTERITY) ||
(obj->which_kind == ADD_STRENGTH)) {
sprintf(more_info, "%s%d ", ((obj->class > 0) ? "+" : ""),
obj->class);
(void) strcat(desc, more_info);
}
}
(void) strcat(desc, item_name);
(void) strcat(desc, id_table[obj->which_kind].real);
break;
case WAND:
(void) strcat(desc, item_name);
(void) strcat(desc, id_table[obj->which_kind].real);
if (wizard || obj->identified) {
sprintf(more_info, "[%d]", obj->class);
(void) strcat(desc, more_info);
}
break;
case ARMOR:
sprintf(desc, "%s%d ", ((obj->d_enchant >= 0) ? "+" : ""),
obj->d_enchant);
(void) strcat(desc, id_table[obj->which_kind].title);
sprintf(more_info, "[%d] ", get_armor_class(obj));
(void) strcat(desc, more_info);
break;
case WEAPON:
sprintf(desc+strlen(desc), "%s%d,%s%d ",
((obj->hit_enchant >= 0) ? "+" : ""),
obj->hit_enchant,
((obj->d_enchant >= 0) ? "+" : ""),
obj->d_enchant);
(void) strcat(desc, name_of(obj));
break;
}
break;
}
ANA:
if (!strncmp(desc, "a ", 2)) {
if (is_vowel(desc[2])) {
for (i = strlen(desc) + 1; i > 1; i--) {
desc[i] = desc[i-1];
}
desc[1] = 'n';
}
}
if (obj->in_use_flags & BEING_WIELDED) {
(void) strcat(desc, "in hand");
} else if (obj->in_use_flags & BEING_WORN) {
(void) strcat(desc, "being worn");
} else if (obj->in_use_flags & ON_LEFT_HAND) {
(void) strcat(desc, "on left hand");
} else if (obj->in_use_flags & ON_RIGHT_HAND) {
(void) strcat(desc, "on right hand");
}
}
svo, wtflol. what_is!
svo: Yikes!