Remix.run Logo
BobbyTables2 11 hours ago

TLDR: For almost 1/6 of a century, the C++ standards broke the simplest infinite loop and only just recently fixed it.

Idiots!

Don’t they really that people write real programs to solve real problems? This isn’t a theoretical academic exercise!

Sharlin 11 hours ago | parent | next [-]

The argument is that an infinite loop without side effects isn't a real program. It's not useful for anything except wasting cycles.

nh2 10 hours ago | parent | next [-]

Of course the infinite loop should run as expected.

It breaks the most fundamental debugging expectations (such as "delete code until problem disappears") if the fundamental, minimal building blocks of a language, when on their own, do random rubbish.

To understand a program that does something, better first understand a program that does nothing.

As a fan of sensible analogies:

You put a salad bowl with vinegar into the fridge and notice that when you do that, the fridge stinks afterwards. You try again without the vinegar, then without the salad. In C++ world, upon receiving the empty bowl, the fridge detonates ("it is not useful"), blowing up your house. That is not OK.

Jaxan 10 hours ago | parent [-]

But if you program a for loop computing the sum from 1 to n, this also gets replaced by a constant (unless you build in debug mode). Why would an empty loop be different?

vlovich123 10 hours ago | parent [-]

I think the argument is that the equivalent of an infinite loop would be a halt / abort instruction, not a complete removal of the loop and continue running anything else.

rcxdude 9 hours ago | parent [-]

Not necessarily what you want in that case either: it's a common pattern in cases where you want the system to halt until you can attach a debugger to inspect the state. A halt/abort instruction that trashes that state would be undesirable (some CPUs have an instruction that is equivalent, but many do not, after all, why bother if you can just write an infinite do-nothing loop?).

kibwen 11 hours ago | parent | prev | next [-]

And unfortunately that argument would be incorrect, because not only is there a realistic chance of hitting this on embedded systems, the fact that LLVM baked this into its low-level semantics resulted in miscompilations in Rust for a time, where `loop {}` is a valid way to implement a diverging function: https://github.com/rust-lang/rust/issues/28728

lou1306 10 hours ago | parent | prev [-]

Yeah the argument here is clear, also rather silly. Either you must accept that your language allows for completely useless computation, or, if the compiler is so good at detecting "unreal programs" it should also refuse to compile them.

Panzerschrek 8 hours ago | parent | prev | next [-]

> the simplest infinite loop

An infinite loop which does nothing is practically useless. So, compilers optimize it out. That's the whole philosophy of modern compilers - to reduce execution time by preserving semantics. In case of an infinite loop elimination it's an optimization making code infinite times faster.

bryanlarsen 11 hours ago | parent | prev | next [-]

They also realized that people choose compilers based on performance benchmarks, and that insane optimizations let them win.

vlovich123 11 hours ago | parent [-]

Until Rust proved actually you can get really good or better performance if the language itself is better. I really don’t know how C++ digs itself out of the UB hole it has dug.

bryanlarsen 11 hours ago | parent [-]

Probably by working together with Rust. Eliminating undefined behavior from unsafe Rust is a big deal for the Rust community at the moment. And given that most unsafe rust code exists to call into C or C++, concepts like pointer provenance need to be extended. And proper pointer provenance guarantees can both decrease UB and increase optimization potential.

IIUC, my understanding is shallow.

vlovich123 10 hours ago | parent | next [-]

That's a niche level thing that helps in some scenarios, and generally not as much for C++ which is much more weakly typed than Rust is. Weak typing + static typing is why safety problems in C++ are going to be really difficult to fix without fundamentally changing the language.

bryanlarsen 9 hours ago | parent [-]

I expect some changes to the language from this direction, some way to attach provenance information or limitations to a pointer. Presumably through a #pragma at first. Strict typing in the C++ sense, not the Rust sense. An annotation like "volatile".

Pointer provenance is just one example, there are others.

nicoburns 11 hours ago | parent | prev [-]

This particular case is likely an example of that. Rust used to have this problem, but it wasn't ever intended to. So IIRC it got fixed in LLVM for Rust, and this is probably now C++ taking advantage of that.

11 hours ago | parent | prev | next [-]
[deleted]
bluGill 11 hours ago | parent | prev [-]

You are an idiot if you write an infinite loop. An infinite loop is a waste of CPU cycles and energy when run.

If it wasn't so hard to detect (the trivial cases are easy, but it gets hard quickly) I'd say the program should fail to compile.

dare944 9 hours ago | parent | next [-]

And where to you think all that "wasted" energy/cycles would go otherwise? Why do you presume there's some other, more efficient way the CPU could be spending its time while waiting for an event to process?

I, the programmer, will decide what cycles are wasted or not. That the C++ committee thought they knew better is hubris.

bluGill 6 hours ago | parent [-]

If the CPU halts it isn't used at all. If the CPU does an infinite loop then it all goes to heat.

If the loop is doing anything then it cannot be optimized away. Only loops with no side effects meaning they are just turning the CPU into a heater count.

echoangle 10 hours ago | parent | prev | next [-]

And how would you generate assembly to keep a microcontroller idle then?

bluGill 10 hours ago | parent [-]

You call the CPU halt instruction.

echoangle 10 hours ago | parent [-]

What if my CPU doesn't have that? I don't think Atmel Microcontrollers do for example.

bluGill 9 hours ago | parent | next [-]

Better CPU selection. Embedded almost always have power requirements and you need to put your CPU into a low power mode not a loop which is running fast. You can also design your hardware such that you can turn the power off completely in these cases (or perhaps reboot).

Now that I think of it, a different project (I worked just down the aisle, but I wasn't on it) solved a lot customer complaints by turning all the "while(1);" loops into blink an error code - which since it does IO is defined behavior. Which probably is the correct answer to your question - don't just spin doing nothing, spin in such a way that the user has a clue why nothing is working (and in turn you can find out and perhaps fix real world bugs)

dare944 8 hours ago | parent [-]

This is myopic. In many cases it takes time, and sometimes considerable programming effort, to enter and exit low power modes. So you don't do it willy-nilly; you do it when you believe the system has quiesced. That means, on a purely interrupt driven system that is not yet ready to sleep, the code may very well be spinning in an empty infinite loop somewhere.

There's no need to inform the "user" because there's nothing wrong with the system. Its simply waiting until the benefit of sleeping outweighs the cost of getting there.

bluGill 6 hours ago | parent [-]

The context here is an infinite loop with no side effects. You have all the time needed to enter those states.

dare944 5 hours ago | parent | next [-]

It may take 100s of instructions to enter a deep sleep state, and 100s to 1000s more to exit it. If you anticipate having to service an event sooner than that, you don't enter sleep at all (especially since there's likely a point at which you're committed to sleep, and have to go all the way down in order to come right back out again). Instead, you hang around twiddling your thumbs until the event comes along.

Now if your processor has a halt/wait-for-interrupt instruction (most do but some don't) you can escape into assembly and use that. But it probably makes little to no difference to energy utilization, and of course its not portable. A nice while (true); would seem obvious, except that the C++ committee insisted that it wasn't.

Just one example of where the committee lost sight of the fact that it was defining an imperative programming language.

echoangle 6 hours ago | parent | prev [-]

Not necessarily, you could also want to make an infinite loop and wait for an interrupt without eanting to power down.

AMDmi3 8 hours ago | parent | prev [-]

AVRs have SLEEP instruction.

AnimalMuppet 6 hours ago | parent | prev [-]

Non-trivial infinite loops are very much not an "idiot" thing on embedded systems. "Run until power off" or "run until the warhead detonates" are perfectly normal things to do in that world.