4 ms·
Accurate comment of the day. C intentionally leaves behavior undefined to allow flexibility in implementation, which allows implementations to take advantage o
by shadowgovt 3y ago
Accurate comment of the day.
C intentionally leaves behavior undefined to allow flexibility in implementation, which allows implementations to take advantage of optimizations that other languages can't because they are over-constrained for the target architecture.
What's the order of operations for sequence of expressions added together? Do they evaluate left to right or right to left? The answer is, very intentionally, "any order is allowed and order may change between executions of a line." This makes it possible to make C implementations equivalently fast on various architectures where, for example, stacks and stack operation ordering make it more efficient to do one or the other. Hell, the language is even usable in an architecture where each of those expressions could be run purely parallel. Of course, the downside is that you definitely can't assume side effects caused by the left side of an expression occurred before the right side.
But the trade-off is that you do have to be extremely sensitive to making assumptions that the specification doesn't actually specify, or you are going to trip over an error in your assumptions that matters on your implementation. The actual "this is undefined behavior so the program deleted your whole hard drive" scenario is incredibly unlikely on a modern desktop or server architecture, but the languages flexibility does mean that you're perpetually one missed trick away from incredibly perplexing behavior.
This is a feature of the language not a bug. It's how the language gets you as close as it possibly can to the speed you would be able to get hand writing the assembly at every step of the process.
- AlotOfReading 3y agoIt's not a bug only in the sense that it's intentional. It's certainly not "good" or a feature any other language should ever copy again because it prevents you from saying anything formally about the properties of the system at time T, when UB has occurred or will occur at any point along the execution path. As a result, you're always stuck with the qualification that x is true in the absence of UB, something that no automated checker can ever verify and careful review is insufficient to validate in the real world. Whether or not this is a common issue on commodity hardware is basically irrelevant given C's remaining niche. It's mainly the language of kernels, drivers, and firmware nowadays, not primitive CLI tools that can crash whenever they feel like it. Ensuring system state with high reliability is the raison d'etre of modern C, so the lack of ways to do that without significant caveats is incredibly problematic.
- shadowgovt 3y agoThat's the tricky part. As the amount of parallelism required to eke out more performance approaches infinity, the amount we can say about the properties of the system at time T approaches zero. Determinism is actually the enemy here. > It's mainly the language of kernels, drivers, and firmware nowadays, not primitive CLI tools that can crash whenever they feel like it On this we completely agree; I would encourage pushing implementation of command line tools in C as close to zero as possible. It isn't necesary to get maximum performance (either because those tools don't demand it or because we have other langauges that make better safety-performance tradeoffs to get us, on average, as fast as C without sacrificing things like memory-access safety).
- AlotOfReading 3y agoIf we can't say anything about the system at time T, that's a failure of the execution model. I'm not trying to implicate Rice's theorem here or other undecideable problems. C makes it difficult to correctly implement any code (rather than all code) that has a property we want and show that it holds solely with the tools available to mortals. Divine intervention is helpful, but notoriously unreliable.
- shadowgovt 3y agoThis is probably my bias just from all of the distributed work I've had to do, but in general being able to say anything about the state of the system at a discrete time T is an expensive luxury in my ecosystem, If not actually infeasible. You can say things about the expected input and output, you can reason about how it's supposed to get there, and you can do traces of a discrete path that was taken in hindsight. But being able to pause the universe and say "What is the current state of the machine" isn't possible when the 'machine' is spread across data centers in multiple geographic locations and it's barely, if we turn our head and squint and lie to ourselves, possible on a modern CPU architecture with SIMD instructions and branch prediction.
- AlotOfReading 3y ago