This is one of the problems in these discussions about undefined behavior: some people feel very strongly about topics they are entirely unfamiliar with.
According to the C++ standard, “undefined behavior may be expected when this document omits any explicit definition of behavior
or when a program uses an erroneous construct or erroneous data.” Some examples of undefined behavior still lead to the correct execution of a program, but even so the rule of thumb is to interpret all instances as wrong already.
some people feel very strongly about topics they are entirely unfamiliar with.
Some people also feel strongly about topics they are very familiar with 🙂. I have experienced my fair share of undefined behaviour in C++ and it has never been a pleasant experience.
Some examples of undefined behavior still lead to the correct execution of a program, but even so the rule of thumb is to interpret all instances as wrong already.
Sure, sometimes use of undefined behaviour works, but this is more dumb luck than a rule of thumb that you should use. The idea of “it’s undefined behaviour but it works when I test it so it’s fine” is downright dangerous. That kind of careless attitude might be okay for your hobby projects with low stakes, but for any serious professional software development, you’re setting a landmine for yourself and/or your coworkers, employer and users.
Undefined behaviour might work when you test it and it might work when you run it the 1000th time. At the same time it may fail on the 1001st run and it can also easily completely fail when compiling again or simply compiling with a different compiler version. Undefined behaviour is not predictable and is always wrong.
Some people also feel strongly about topics they are very familiar with 🙂. I have experienced my fair share of undefined behaviour in C++ and it has never been a pleasant experience.
If you had half the experience you claim to have, you’d know that code that triggers UB is broken code by definition, and represents a bug that you introduced.
It’s not the language’s fault that you added bugs to the code. UB is a red herring.
Sure, sometimes use of undefined behaviour works (…)
You missed the whole point of what I said.
By definition, UB does not work. It does not work because by design there is no behavior that should be expected. By design it’s up to the implementation to fill in the blanks, but as far as the language spec goes there is no behavior that should be expected.
Thus, code with UB is broken code, and if your PR relies on UB then you messed up.
Nevertheless, some implementations do use UB to add guardrails to typical problems. However, if you crash onto a guardrail, that does not mean you know how to drive. Do you get the point?
It’s not the language’s fault that you added bugs to the code.
Nobody’s perfect and time has shown multiple time that you can’t trust human beings with memory safety. I.e. the whole 70% of bugs being memory safety bugs thing. Adding bugs to the code isn’t the language’s fault, but you can’t blame a human being (even experts) to do it.
It is however the language’s fault to allow UB in the first place. And it’s possible to entirely avoid UB in (safe) Rust. So we’ve seen that the possibility of undefined behavior is not necessary for the vast major of programming. So I would definitely say it’s C and C++'s “fault” for allowing UB in the unrestricted way that it does.
Am I blaming those languages? Nah, it was a different time. We didn’t have the technology we have now. But going forward there’s no reason to use unsafe languages in greenfield projects. We should move forward with safe languages.
Nobody’s perfect and time has shown multiple time that you can’t trust human beings with memory safety.
That’s perfectly fine. That’s not a problem caused UB, or involving UB.
Again, UB is a red herring.
It is however the language’s fault to allow UB in the first place.
It really isn’t. Again, mindlessly parroting this doesn’t give any substance to this claim. Please try to think about it for a second. For starters, do you believe it would make any difference if the C or C++ standard defined how the language should handle dereferencing a null pointer? I mean, in some platforms NULL is a tombstone, but on specific platforms NULL actually points to a valid memory address. The standards purposely leave this as undefined. Why is that? Seriously, think about it for a second.
Am I blaming those languages? Nah, it was a different time.
It really isn’t. It’s a design choice that reflects the need to work with the widest possible range of platforms. The standards have already been updated with backwards-incompatible changes, but even the latest revisions purposely include UB.
I repeat: I see people mindlessly parroting nonsense about UB when they clearly have no idea what they’re talking about.
what is the usecase for going beyond maxint? Sure I can make it defined, but your program will have a bug if you do it. Defined just means platforms with a different behavior have to insert checks all over for something that rarely haypens
Okay but I would much rather deal with a defined bug than an undefined one. A defined bug is still a bug, but at least it is predictable. A bug from undefined behaviour is chaos and could do conceivably anything.
A defined bug is at least somewhat limited in what it can do. In Rust, many of those cases would panic for instance. That’s much better than, say, continuing execution with garbage data.
Those programs are wrong already. you can insert lots of checks and slow down correct code, but that results are still wrong as the code has a bug.
What do you mean wrong “already”?
This is one of the problems in these discussions about undefined behavior: some people feel very strongly about topics they are entirely unfamiliar with.
According to the C++ standard, “undefined behavior may be expected when this document omits any explicit definition of behavior or when a program uses an erroneous construct or erroneous data.” Some examples of undefined behavior still lead to the correct execution of a program, but even so the rule of thumb is to interpret all instances as wrong already.
Some people also feel strongly about topics they are very familiar with 🙂. I have experienced my fair share of undefined behaviour in C++ and it has never been a pleasant experience.
Sure, sometimes use of undefined behaviour works, but this is more dumb luck than a rule of thumb that you should use. The idea of “it’s undefined behaviour but it works when I test it so it’s fine” is downright dangerous. That kind of careless attitude might be okay for your hobby projects with low stakes, but for any serious professional software development, you’re setting a landmine for yourself and/or your coworkers, employer and users.
Undefined behaviour might work when you test it and it might work when you run it the 1000th time. At the same time it may fail on the 1001st run and it can also easily completely fail when compiling again or simply compiling with a different compiler version. Undefined behaviour is not predictable and is always wrong.
See also https://predr.ag/blog/falsehoods-programmers-believe-about-undefined-behavior/
If you had half the experience you claim to have, you’d know that code that triggers UB is broken code by definition, and represents a bug that you introduced.
It’s not the language’s fault that you added bugs to the code. UB is a red herring.
You missed the whole point of what I said.
By definition, UB does not work. It does not work because by design there is no behavior that should be expected. By design it’s up to the implementation to fill in the blanks, but as far as the language spec goes there is no behavior that should be expected.
Thus, code with UB is broken code, and if your PR relies on UB then you messed up.
Nevertheless, some implementations do use UB to add guardrails to typical problems. However, if you crash onto a guardrail, that does not mean you know how to drive. Do you get the point?
Nobody’s perfect and time has shown multiple time that you can’t trust human beings with memory safety. I.e. the whole 70% of bugs being memory safety bugs thing. Adding bugs to the code isn’t the language’s fault, but you can’t blame a human being (even experts) to do it.
It is however the language’s fault to allow UB in the first place. And it’s possible to entirely avoid UB in (safe) Rust. So we’ve seen that the possibility of undefined behavior is not necessary for the vast major of programming. So I would definitely say it’s C and C++'s “fault” for allowing UB in the unrestricted way that it does.
Am I blaming those languages? Nah, it was a different time. We didn’t have the technology we have now. But going forward there’s no reason to use unsafe languages in greenfield projects. We should move forward with safe languages.
That’s perfectly fine. That’s not a problem caused UB, or involving UB.
Again, UB is a red herring.
It really isn’t. Again, mindlessly parroting this doesn’t give any substance to this claim. Please try to think about it for a second. For starters, do you believe it would make any difference if the C or C++ standard defined how the language should handle dereferencing a null pointer? I mean, in some platforms NULL is a tombstone, but on specific platforms NULL actually points to a valid memory address. The standards purposely leave this as undefined. Why is that? Seriously, think about it for a second.
It really isn’t. It’s a design choice that reflects the need to work with the widest possible range of platforms. The standards have already been updated with backwards-incompatible changes, but even the latest revisions purposely include UB.
I repeat: I see people mindlessly parroting nonsense about UB when they clearly have no idea what they’re talking about.
what is the usecase for going beyond maxint? Sure I can make it defined, but your program will have a bug if you do it. Defined just means platforms with a different behavior have to insert checks all over for something that rarely haypens
Okay but I would much rather deal with a defined bug than an undefined one. A defined bug is still a bug, but at least it is predictable. A bug from undefined behaviour is chaos and could do conceivably anything.
A defined bug is at least somewhat limited in what it can do. In Rust, many of those cases would panic for instance. That’s much better than, say, continuing execution with garbage data.
There are many examples of applications that leverage integer overflow, either wrapping around or saturating values.