15 ms·
There's a parable where a man goes to the doctor and says, "Doctor, whenever I drink my coffee with the spoon in the cup, the spoon handle pokes me in the eye a
by copsarebastards 11y ago
There's a parable where a man goes to the doctor and says, "Doctor, whenever I drink my coffee with the spoon in the cup, the spoon handle pokes me in the eye and it hurts." And the doctor says, "Well, stop doing that."
If you wrote `foo(bar(), baz())` and `baz()` relies on state mutated by `bar()`, your code is bad, and you should feel bad, because experiencing those bad feelings is the way you learn to not write bad code. This code was wrong before the compiler reordered the calls, it just failed silently for a while. The compiler isn't responsible for fixing your bugs, you are.
People need to stop expecting other people to fix their problems.
- snarfy 11y agoIf bar() returned the mutated state, he could just do: foo(baz(bar()))
- copsarebastards 11y agoI think a better design would be to separate mutators from pure functions. If a procedure mutates state, it should have a void return type, and if a procedure returns a value it should be a pure function that doesn't mutate state. This is, of course, a rule of thumb, not a hard law. Some exceptions: 1. I think it's okay (and in fact, idiomatic in C) to mutate state and return some sort of information about what occurred (i.e. a success flag, a number of characters written, etc.). 2. Isolated mutations such as logging sometimes make sense in an otherwise pure function.
- snarfy 11y agoI'm a fan of fluent design myself, and dislike flags. return foo().baz().bar(); With flags you start with success/fail, and end up with HRESULT.
- copsarebastards 11y agoI'd agree with you in some languages, but in C this would be prohibitively difficult. In general, good fluent design uses immutable objects, which makes it basically just a syntactic sugar for functional programming. While fluent syntax is nice, the functional semantics are the real value, and are much easier to do in C (although, as soon as you add in memory management, functional programming often becomes prohibitively difficult too).
- zzalpha 11y agoUhh... The question was "what's an example of undefined behaviour". I gave one, specifically of an example that could realistically break by relying on undefined behaviour. That's it. Simple education. In the context of this post I think that's a good thing because not everyone will understand the topic. You, however, seen to have read some sort of agenda in the question, which I find a little baffling...
- copsarebastards 11y agoYou're right; I'm sorry for misreading your intention. I've edited my post so it's not as directed at you.
- Dylan16807 11y agoBut that's not "undefined behavior" either. The post misleads people. Certain things are unspecified. It can call in any order for example. Other things are undefined. If you do them your program is no longer valid at all, and can crash or corrupt.
- nitrogen 11y agoTo reiterate/emphasize this point: "undefined", "unspecified", and a few other related terms are Things in C. They have specific, non-interchangeable, well-defined meanings in the C specifications.
- dvogel 11y agoWho is at fault in your example becomes much less clear cut when you consider the variant where the author of foo doesn't have access to the source code of bar and baz and they only rely on shared state on some systems or in some corner cases.
- dbaupp 11y agoThe eye-spoon defence of C undefined and unspecified behaviours is very unfortunate and misleading: it makes it sound like avoiding them is as easy as just taking a spoon out of a cup. Theoretically "stop doing that" works... but history has shown that it really doesn't work in practice, in C, in programming more broadly, and, really, in any human endeavour ("planes don't need safety procedures, just stop making mistakes").