On Thursday, October 12, 2017 21:22:29 kdevel via Digitalmars-d-learn wrote: > On Thursday, 12 October 2017 at 20:27:03 UTC, Jonathan M Davis > > wrote: > > On Thursday, October 12, 2017 20:15:41 kdevel via > > > >> --- > >> void main () > >> { > >> > >> assert (false); > >> > >> } > >> --- > >> > >> qualifies as "invalid, and therefore has undefined behaviour." > >> A statement, which makes no sense to me. Either it is a > >> "debugging aid", that implies defined behavior, or it is > >> undefined behavior, then assert (false) cannot aid debugging. > > > > assert(false) is a bit special in that it's never removed (it > > becomes a HLT instruction with -release), > > Confirmed. I should have written something like this instead: > > --- > import std.stdio; > import std.string; > import std.conv; > void main () > { > int i; > i = readln.chomp.to!int; > assert (i != 3); > writeln ("i = <", i, ">"); > } > --- > > Is it defined that this program throws an AssertError in debug > mode if 3 is fed to stdin? If not, assert (...) could not aid > debugging.
If assertions are compiled in (which they are if you're not compiling with -release), and i is ever 3, then an AssertError will be thrown. This is guaranteed. As such, the compiler is free to assume that i is never 3 when code execution arrives at the line after the assertion, and if it can do an optimization based on that fact, it is free to do so. You've told it that i should never be 3 at that point and that it's a bug if it is, and as such, it is free to assume that i is never 3 after the assertion even if the assertion is compiled out with -release - that is the only place that undefined behavior may enter into it. If the compiler does an optimization based on the fact that i isn't 3, and it is, and -release is used, then you could get some weird behavior when the code reaches the lines after the assertion - but by definition, you already have a bug if i is 3, and your program in general is assuming that i isn't 3 at that point, so you're going to get bad behavior either way. The fact that your assertion failed means that you have a logic error in your program, and it is therefore in an invalid state and will likely not behave correctly. However, your example is an excellent example of when _not_ to use assertions. Assertions should never be used on user input or anything outside of the program's control. When you use an assertion, you are saying that it is a bug in the progam if that assertion fails, and bad user input isn't a bug, though the fact that you're not validating user input arguably is (certainly it is if the assertion is there, since at that point, you're saying that it's a bug if i is ever 3). Assertions allow you to catch bugs in your logic during development and then don't slow your program down when compiling with -release for production. They are not for validating anything other than that the logic of your program is correct. And if for any reason, you're paranoid enough that you want those logic checks to still be there in production, then either don't use -release (even in production), or do something like enforce!Error(cond, "msg"); instead of assert(cond, "msg); and then you'll get an Error thrown when the condition fails - even with -release. On a side note, I would point out that talking about "debug mode" with D gets annoyingly ambiguous, because that kind of implies the -debug flag, which has nothing to do with assertions and which actually can be used in conjunction with -release (all -debug does is enable debug{} blocks), which is why I try to avoid the term debug mode - though I assume that you meant when -release isn't used, since that's often what folks mean. - Jonathan M Davis