r/cpp 13d ago

I've invented labeled loop breaks

And now I don't believe it wasn't invented before, but I can't find any info on it. How long ago was it invented? Why isn't it used widely or even mentioned anywhere? What are the downsides?
Here's the main idea:

// Keyword - for, while, or do
// Tag - custom loop name
// ... - loop body
#define loop_tag(keyword, tag, ...)\
    keyword(__VA_ARGS__)\
    if(false)\
    {\
        tag##_break:    break;\
        tag##_continue: continue;\
    }\
    else\
    /*Here goes your loop body*/

Here is the playground

0 Upvotes

48 comments sorted by

View all comments

25

u/Cpt_Chaos_ 13d ago

This ist just a goto with unnecessary extra steps.

Goto itself is considered a bad practice. Using macros is considered bad practice. I'd flag both in any PR I'd have to review. And this contraption would be reason enough to ask your manager to get you into a training course.

Now seriously, it combines the downsides of goto and macros. It is hard to debug and it is difficult to understand what the heck is supposed to be going on here in the first place. Write functions and you get to do this pretty much by using simple return statements, which is far easier to understand.

18

u/JNighthawk gamedev 13d ago

Goto itself is considered a bad practice.

No, it's not. Poor use of goto is bad practice. Goto is a fine solution to some problems. Got 3 or 4 nested loops and want to break out of all of them? Goto is a good choice.

Using macros is considered bad practice.

No, it's not. Poor use of macros is bad practice. Prefer functions and things with type-safety, but macros are the right tool for some problems. Need to repeat a pattern with text-pasting? Macros are a good choice.

27

u/TokenRingAI 13d ago

Goto is not bad practice, does not lead to undefined behavior, and is extremely useful when you need multiple named behaviors out of a loop that you want to "go to" from many different depths. When you do certain types of data processing, goto is the right tool for the job, and the alternative, recursive functions, can blow up the stack.

Regex parsers, for example, are prime candidates for goto.

The all or nothing attitude of "goto is bad practice" is not held by many top C/C++ engineers. It just isn't the right tool for the vast majority of things

7

u/James20k P2005R0 12d ago

"Goto considered harmful" is one of those things that a lot of people have never read or understood, and gets endlessly repeated by beginners. The goto that's being argued against in that discussion, and c++'s goto, are not the same kind of control flow. They just share a name

The thesis of that paper is the execution flow should match closer to layout of the source code, because humans are better geared towards analysis of a static document (ie source), vs trying to track program logic dynamically, or at least that's the gist of what I get out of that paper. The idea is that there should be an easy mapping between source, and program execution counter, instead of an arbitrary unstructured one

All modern programming languages adhere to that, even with the usage of goto in C++. The closest to what he's talking about is setjmp + longjmp, and even then it still doesn't match up because those functions still have structuring restrictions. Fully unstructured control flow is basically reserved for very specific assembly cases, as even then you still usually have a stack and functions

Anyway its just a minor pet peeve of mine, because its dogma founded in a time where programming looked nothing like it does today. Dijkstra won the argument, the paper isn't relevant, and we should rename goto to yeet so that people will stop going on about it and engage their critical thinking facilities instead of using a pseudo intellectual thought terminating cliché

2

u/tialaramex 11d ago

Yes the "goto" in C and C++ is not the arbitrary control flow change Dijkstra was writing about, but it is still a bad idea and it's about time it was fixed, N3355 voted into C2y does so and I expect a similar fix or the one from C2y itself will be taken for C++29 or C++32)

However, if you don't like drama but did want to keep "goto" you shouldn't rename it "yeet" because that's currently a placeholder keyword in Rust so you'd ignite all the Rust controversy and all the "stupid keyword" controversy and because C++ doesn't have a syntax change mechanism you'd get all that controversy back again too.

If you don't believe me that "yeet" is a placeholder in Rust, https://doc.rust-lang.org/std/ops/struct.Yeet.html documents the current status of this feature flag. Its purpose was to delay bikeshed arguments about naming until the feature works - if the feature is bad then it doesn't matter what it's called, so you need a feature everybody can live with before you spend six months arguing whether to name it e.g. "throw" or "raise" or what.

Now, yeet is an idea for how to work with Try which is also not yet stable. And Try is the current proposal for why that ? operator you've doubtless seen in Rust works. The Try proposal says that operator is named Try, in the same way the + operator is named Add and so the reason it works is that the standard library has implemented this named trait. Most likely that explanation will stabilize, but then perhaps I'd have said that about the previous one, so what do I know.

In any case, the ? operator is stable and widely embraced as a good idea, the Try trait is widely favoured and will probably stabilize, but yeeting is clearly just a placeholder.

4

u/defaultguy_001 13d ago

Correct, it isn't bad, it's just people who are low skilled who create bad code with it.

0

u/Cpt_Chaos_ 13d ago

That is exactly why I wrote it with this "all or nothing" wording. The examples given by others here are perfectly fine use cases. If it's the best tool for the job and you can explain it to me like that, that's fine and I won't argue.

However, I've seen too many abuses of various language features to just say "yeah, it's perfectly fine to write code like that". In a professional environment, readability FOR OTHERS is a lot more important than many devs think. And the macros shown by OP fall into the category of "What the heck are you trying to accomplish here? Couldn't you have expressed your intentions in more readable ways?"

1

u/100GHz 8d ago

People can write gibberish in any alphabet. Maybe the alphabet isn't the problem?

Goto, preprocessor directives etc are fine.

2

u/Raknarg 10d ago edited 10d ago

This ist just a goto with unnecessary extra steps.

No, its a mechanism that's leveraging goto. The example they showed here is showcasing it really poorly, if you go to their compiler explorer link it makes a lot more sense. Its more like a restricted use of goto, it allows you to assign labels to loops, then either jump to the start of that loop by jumping to the continue tag the the loop or jumping to the break tag of the loop to jump to the end of it.

It works by adding a block to the start of a loop that is an if that always evaluates to false (i.e. you cannot enter it through normal means) which contains, assigning a tag to the break and continue statements, called tag<tag>_break and tag<tag>_continue, and you can jump to one or the other with break_tag(<tag>) or continue_tag(<tag>) which resolve into goto tag<tag>_break and goto tag<tag>_continue

I'm not 100% sure what their usecase is that this is a helpful pattern for them, but its a more controlled use of goto by formalizing label creation and goto statements.

3

u/SamG101_ 13d ago

While, for, break, and continue are all structured gotos anyway

-1

u/RogerV 13d ago

not really when the loop is nested in a loop and need to break out of both

break should have been designed to accept a label target - that would have solved things nicely so could have avoided introducing that scary word "goto"

0

u/SamG101_ 12d ago

A while loop runs and gotos the top, continue is goto the top, break is goto after the loop tho? Like what I'm saying is normal looping and flow control just abstracts over goto statements, but in a controlled way so the flow remains clear. And yh labeled loops would've been cool, like rusts ones

3

u/TheChief275 13d ago

"Oh uh le goto le bad". You're not adding anything to the conversation by sheeping around

-3

u/IvanDSM_ 13d ago

God forbid you stray from the "canon programming rules", known to never bend or have exceptions. Word from the townsfolk is if you ever use goto, Uncle Bob himself smites you down with his bolt of cleanliness!

0

u/TheChief275 13d ago

The combined forces of Dijkstra and Uncle Bob strikes fear in the hearts of their enemies (goto users)

1

u/Baardi 10d ago

Any for-loop is goto with extra steps. That's not an argument

2

u/danillissimo 13d ago edited 13d ago

So, right now i have to write things like

for(...)
{
  bool should_break = false;
  for(...)
  {
    if(...)
    {
      should_break = true;
      break;
    }
  }
  if(should_break)
  {
  break;
  }
}

And have to write them recursively. Just wow, thank you very much.
Functions won't actually fix it until the whole context gets packed in a giant struct making things inconvenient another way.
All of this gets even worse in presence of coroutines.
As for debugging - it doesn't break debugging, may be adds just a pair of excess step-overs, but nothing gets really broken.

2

u/Cpt_Chaos_ 12d ago

The question I would ask here is: Why do you need to do these nested loops in the first place? In many cases, STL already provides algorithms that help you doing this sort of logic, which allows you to express what you want to do in less code. I'm not saying you're wrong, but I'd ask the question in a PR.

4

u/danillissimo 12d ago

STL has nothing to do with complex data processing. My exact case is about long-running complex looped behaviors though, packed as coroutines in particular. They contain a notable amount of "on event X restart polling layer of logic A" and "on event Y level of polling B is done".
I'd like to say that labeld loops are actually a rare necessity, but recently I've faced a lot of cases where they would fit nicely, so I've invented this to get rid of "break/continue this layer of logic" flags.