4 ms·
An expression like my_func(a++, a) is confusing on all fronts - the intention isn't clear for the compiler, for the code reviewer, for the programmer themselves
by passivate 5y ago
An expression like my_func(a++, a) is confusing on all fronts - the intention isn't clear for the compiler, for the code reviewer, for the programmer themselves when they read it 5 years from now, for the next-in-line bloke who gets handed this code to maintain it, etc.
My point was about whether C++ screws you over with UB when the programmers intention can be argued to be obvious. I don't think it does. But I will stand corrected if someone can show me what they're talking about.
It seems like people are making this into a discussion about C++ being a difficult language to learn - which I am not defending.
- Etherlord87 5y ago> My point was about whether C++ screws you over with UB when the programmers intention can be argued to be obvious. Incrementing a number is obvious and results with UB if incremented past the maximum. Since you get no guarantee whatsoever how the UB will be handled (hence the joke with the end of the space-time, or nasal demons etc.), by my understanding (that I think many experts share), it can indeed screw you up. Of course you may say a programmer should expect this to happen and so it's just a bug - every UB is. > It seems like people are making this into a discussion about C++ being a difficult language to learn I think it's more than that. Even assuming that you never caused UB yourself, you can still work on someone else's code with UB and need to debug it. So C++ is hard to learn AND use.
- passivate 5y ago>if incremented past the maximum. What would be the intention to increment past the maximum? Incrementing a number infinitely is an infinite series 1+1+1[..] A programmer needs to be aware that you cannot store an infinite series in a data type like int - and this applies to any programming language. If the programmer is looking to exploit wrapping behavior then it is best not to ASSUME anything, but actually verify what promises the language provides. Its basic sanity checking, you do that before sending parameters to API, receiving parameters, during transfer of ownership of memory, etc, etc. All of this falls under basic programming - regardless of language.
- Etherlord87 5y ago> A programmer needs to be aware This can be extrapolated to anything that causes UB. A programmer needs to be aware that what he does causes UB. You asked for a normal thing that is being done by a programmer that causes UB, and I think I gave a fair example. I don't want to aggressively argue a point, just wondering what exactly you want to prove here. It's not like programmers cause UB intentionally or when doing some weird stuff like code golfing. No, programmers code in C++ using standard techniques and fall victim to the UB. Another example of UB is accessing an array out of bounds. Again, you may say a programmer is expected to rationalize his code in this regard, and yet off-by-one is one of the most common categories of errors in practice.
- passivate 5y ago>You asked for a normal thing that is being done by a programmer that causes UB, and I think I gave a fair example. Not really. I asked for examples where the language takes the intention of the programmer and turns it into UB. The quote that I responded to "C++ compiler generates the most efficient thing that may or may not correlate with what you intended" What is the intention of the programmer attempting to store an infinite number series in an int? In any case, I think we've run of steam here so you have the last word if you'd like.
- tialaramex 5y ago> An expression like my_func(a++, a) is confusing on all fronts - the intention isn't clear for the compiler, for the code reviewer, for the programmer themselves when they read it 5 years from now, for the next-in-line bloke who gets handed this code to maintain it, etc. There are two choices here which result in this confusion. C++ made those choices, which you admit are confusing. Other languages did not. First choice, C++ has the pair of increment operators from C. These operators are a bad idea, so many modern languages either nerf them (e.g. only provide one as a statement like Go) or abolish them altogether (e.g. Rust or Swift). Second choice, unspecified order of evaluation. In principle the idea here is - maybe we can go faster by making different choices depending on context. In practice the price paid for this potential optimisation is high and the reward dubious. So several modern languages just explicitly define the evaluation order instead. Thus in something like Rust you can't write my_func(a++, a) but you can write my_func(a+=1, a) and while that's a weird thing to write in Rust it doesn't lead to real confusion let alone Undefined Behaviour. The arguments are evaluated left-to-right, the first argument seemingly increments a and its result is an empty tuple (because it's an assignment), the second argument is a, the variable we recently incremented. Here's an example where a is an unsigned pointer-sized integer: https://play.rust-lang.org/?version=stable&mode=debug&edition=2021&gist=196c5489e9ec3008c573526f10f4ecef https://play.rust-lang.org/?version=stable&mode=debug&editio... Sure enough with a set to 4000 our output says the second parameter was 4001.
- passivate 5y agoAll you're saying is C++ lets you write bad code. I don't accept that such code is normal in C++ - it isn't. Will someone address my original question? Here it is again: "What normal C++ syntax are you referring to that generates undefined behavior? " The context being that C++ breaks the promise with the programmer by deviating from what was originally intended and generating UB.
- tialaramex 5y agoYou conspicuously don't offer any large bodies of C++ you've written that we could use to provide examples of what "normal" is for you, and so you can feel free to dismiss anything we say as just not "normal" and so irrelevant. For example if I propose that you might foolishly try to multiply unsigned 16-bit integer variables together, I'm sure you'll say that isn't "normal". Or if I proposed you might try to use the C++ stdlib filesystem API on a server which runs other software, doubtless again that just isn't "normal". And so in each case you can feel comfortable that your "normal" C++ is fine. It is effectively a No True Scotsman argument, all the examples that would prove you wrong aren't "normal" according to you.