digitalmars.D - John Regehr on "Use of Assertions"
- Walter Bright (10/10) Sep 01 2018 https://blog.regehr.org/archives/1091
- Guillaume Boucher (23/38) Sep 01 2018 You only read what you want to hear or what?
- Walter Bright (11/40) Sep 01 2018 He says:
- Nick Sabalausky (Abscissa) (13/22) Sep 01 2018 You're both wrong. ;) Or actually, you're both right...
- Nick Sabalausky (Abscissa) (2/5) Sep 01 2018 That said, it IS a very interesting, well-written article.
- Nick Sabalausky (Abscissa) (2/7) Sep 01 2018 All in all, John is very non-committal about the whole thing.
- Walter Bright (2/3) Sep 01 2018 He probably got tired of arguing about it :-)
- John Carter (11/14) Sep 09 2018 Let's face it, the term "assert" has been poisoned by decades of
- Ola Fosheim =?UTF-8?B?R3LDuHN0YWQ=?= (34/42) Sep 09 2018 There is really no ambiguity... The terminology is widespread and
- John Carter (21/25) Sep 09 2018 Ahh, I so, so wish what you said was true. The endless debates in
- Ola Fosheim =?UTF-8?B?R3LDuHN0YWQ=?= (8/13) Sep 10 2018 Well, it has less to do with "assert" than with how semantics are
- Timon Gehr (9/18) Sep 05 2018 I think you misunderstood what the original post and Guillaumes
- Walter Bright (6/8) Sep 06 2018 I believe that his statement:
- Timon Gehr (23/35) Sep 08 2018 Wait, what?
- Jonathan M Davis (24/34) Sep 01 2018 Personally, my concern about letting the compiler optimize based on
- John Colvin (27/71) Sep 02 2018 I believe asserts are the general case of which bounds checking
- Jonathan M Davis (18/32) Sep 02 2018 Well, if that were the intention, then -release could not remove asserti...
- John Colvin (4/23) Sep 03 2018 Yes, the command line interface needs to make it easy and obvious
- Trass3r (5/7) Sep 02 2018 It shouldn't allow side-effects then though.
- Nick Sabalausky (Abscissa) (5/7) Sep 02 2018 This does make me think of one thing: Shouldn't assert expressions be
- Trass3r (6/10) Sep 03 2018 Exactly. You may still catch assert(!fclose(f)) but not other
- Walter Bright (4/13) Sep 05 2018 It's come up before. The trouble comes when the code doing the evaluatio...
- Meta (10/22) Sep 03 2018 I used to completely agree with your position about asserts being
- Ola Fosheim =?UTF-8?B?R3LDuHN0YWQ=?= (11/15) Sep 05 2018 Well, John Regehr seems to argue that you shouldn't use asserts
- Meta (11/26) Sep 05 2018 I don't disagree. I think the only sane way to use asserts as an
- H. S. Teoh (12/21) Sep 05 2018 Sometimes I wonder about a new primitive called 'assume' for optimizer
- Ola Fosheim =?UTF-8?B?R3LDuHN0YWQ=?= (19/28) Sep 05 2018 Yes, if you have an advanced optimizer then it becomes dangerous.
- Trass3r (6/9) Sep 07 2018 Which is the usual behavior of assert.
- Nick Sabalausky (Abscissa) (15/24) Sep 08 2018 I'd certainly agree with this.
- Jonathan M Davis (45/68) Sep 08 2018 I think that it's all about how you look at it. If you look at assertion...
- Ola Fosheim =?UTF-8?B?R3LDuHN0YWQ=?= (9/13) Sep 09 2018 That's the easy solution, but in real world development things
- Michael (5/10) Sep 05 2018 Is the part about the optimizer true in D's case? Or is this just
- H. S. Teoh (10/21) Sep 05 2018 AFAIK, no optimizer currently actually takes advantage of asserts in
- Timon Gehr (9/24) Sep 05 2018 He does not! John gives two definitions. The first definition is the one...
- H. S. Teoh (24/36) Sep 10 2018 [...]
- Neia Neutuladh (5/8) Sep 10 2018 Perhaps we can take some cues from Vigil, the eternally morally
https://blog.regehr.org/archives/1091 As usual, John nails it in a particularly well-written essay. "ASSERT(expr) Asserts that an expression is true. The expression may or may not be evaluated. If the expression is true, execution continues normally. If the expression is false, what happens is undefined." Note the "may or may not be evaluated." We've debated this here before. I'm rather pleased that John agrees with me on this. I.e. the optimizer can assume the expression is true and use that information to generate better code, even if the assert code generation is turned off.
Sep 01 2018
On Saturday, 1 September 2018 at 20:15:15 UTC, Walter Bright wrote:Note the "may or may not be evaluated." We've debated this here before. I'm rather pleased that John agrees with me on this. I.e. the optimizer can assume the expression is true and use that information to generate better code, even if the assert code generation is turned off.You only read what you want to hear or what? His essay is built up in a way where he shows two opposing interpretations of asserts. Assertions as "bug detectors" or as "optimizer hints". He then discusses which one of those is the better one. The quote you gave is the definition from a proponent of the "optimizer hint" camp and not necessarily what John agrees with. His conclusion in the essay is that in general it makes sense to have assertions enabled even in release builds because a slightly worse performance is worth it to have more robust programs and he has backed this up by a lot of examples. Furthermore, he wrote a follow-up post about "assume" (https://blog.regehr.org/archives/1096). Assume seems to be what you think assert is, but there is actually a *huge* difference.We assert a condition when we believe it to be true in every non-buggy execution of our program, but we want to be notified if this isn’t the case. In contrast, we assume a condition when our belief in its truth is so strong that we don’t care what happens if it is ever false. In other words, while assertions are fundamentally pessimistic, assumptions are optimistic.So no, John doesn't agree with you on this *at all*.
Sep 01 2018
On 9/1/2018 3:23 PM, Guillaume Boucher wrote:On Saturday, 1 September 2018 at 20:15:15 UTC, Walter Bright wrote:He says: "Therefore, the compiler should feel free to optimize the program under the assumption that the asserted condition holds. Although this might be what we want — in fact it would be really cool if adding assertions made our code faster rather than slower — it’s not an interpretation that is universally useful. As developers, we might want to count on a certain kind of behavior when an assertion fails." "not ... universally useful" is not quite not agreeing at all.Note the "may or may not be evaluated." We've debated this here before. I'm rather pleased that John agrees with me on this. I.e. the optimizer can assume the expression is true and use that information to generate better code, even if the assert code generation is turned off.You only read what you want to hear or what? His essay is built up in a way where he shows two opposing interpretations of asserts. Assertions as "bug detectors" or as "optimizer hints". He then discusses which one of those is the better one. The quote you gave is the definition from a proponent of the "optimizer hint" camp and not necessarily what John agrees with. His conclusion in the essay is that in general it makes sense to have assertions enabled even in release builds because a slightly worse performance is worth it to have more robust programs and he has backed this up by a lot of examples.Furthermore, he wrote a follow-up post about "assume" (https://blog.regehr.org/archives/1096). Assume seems to be what you think assert is, but there is actually a *huge* difference.I don't interpret it that way. Disabling runtime assert checking turns them into assumes. John is implying asserts should never be disabled.We assert a condition when we believe it to be true in every non-buggy execution of our program, but we want to be notified if this isn’t the case. In contrast, we assume a condition when our belief in its truth is so strong that we don’t care what happens if it is ever false. In other words, while assertions are fundamentally pessimistic, assumptions are optimistic.So no, John doesn't agree with you on this *at all*.
Sep 01 2018
On 09/01/2018 07:54 PM, Walter Bright wrote:On 9/1/2018 3:23 PM, Guillaume Boucher wrote:You're both wrong. ;) Or actually, you're both right... There's a section with the following heading: "Are Assertions Enabled in Production Code?" First sentence of that section: "This is entirely situational." One point for "John agrees with Walter." HOWEVER, Walter has also expressed that a program should never continue after an assert failure. The concluding text of the same section: "[...rather interesting counterexample from NASA/Mars...] The question of whether it is better to stop or keep going when an internal bug is detected is not a straightforward one to answer." One point for "John disagrees with Walter."On Saturday, 1 September 2018 at 20:15:15 UTC, Walter Bright wrote:[Yea-huh, he does.][John agrees with me.][No, he doesn't.]
Sep 01 2018
On 09/01/2018 08:44 PM, Nick Sabalausky (Abscissa) wrote:You're both wrong. ;) Or actually, you're both right...That said, it IS a very interesting, well-written article.
Sep 01 2018
On 09/01/2018 08:44 PM, Nick Sabalausky (Abscissa) wrote:"Are Assertions Enabled in Production Code?" "This is entirely situational." "The question of whether it is better to stop or keep going when an internal bug is detected is not a straightforward one to answer."All in all, John is very non-committal about the whole thing.
Sep 01 2018
On 9/1/2018 5:47 PM, Nick Sabalausky (Abscissa) wrote:All in all, John is very non-committal about the whole thing.He probably got tired of arguing about it :-)
Sep 01 2018
On Sunday, 2 September 2018 at 01:55:53 UTC, Walter Bright wrote:On 9/1/2018 5:47 PM, Nick Sabalausky (Abscissa) wrote:Let's face it, the term "assert" has been poisoned by decades of ambiguity. Come up with another name, (names are free), explicitly define it to mean whatever you mean, explicitly define your intentions, and use it the way you think it should be used, and _never_ use the word "assert" again, . So much pain side stepped. ps: I entirely agree with you on asserts, but years of extremely painful experience tells me, give up on the word now, but not the concept.All in all, John is very non-committal about the whole thing.He probably got tired of arguing about it :-)
Sep 09 2018
On Sunday, 9 September 2018 at 08:31:49 UTC, John Carter wrote:On Sunday, 2 September 2018 at 01:55:53 UTC, Walter Bright wrote:There is really no ambiguity... The terminology is widespread and well understood across the field I think. "assume" means that something is taken as a given fact that has already been established by others. "assert" means that it is something that should be established before shipping. For contracts: "expects" (or "requires") means that the input to a function should have those properties. (precondition) "ensures" means that the returned value should always have those properties. (postcondition) Microsoft GSL let you configure pre/post conditions so that you either get terminate, throw or (much more dangerous) assume on contract violations. They don't seem to provide an option for ignoring it. #if defined(GSL_THROW_ON_CONTRACT_VIOLATION) #define GSL_CONTRACT_CHECK(type, cond) \ (GSL_LIKELY(cond) ? static_cast<void>(0) \ : gsl::details::throw_exception(gsl::fail_fast( \ "GSL: " type " failure at " __FILE__ ": " GSL_STRINGIFY(__LINE__)))) #elif defined(GSL_TERMINATE_ON_CONTRACT_VIOLATION) #define GSL_CONTRACT_CHECK(type, cond) \ (GSL_LIKELY(cond) ? static_cast<void>(0) : gsl::details::terminate()) #elif defined(GSL_UNENFORCED_ON_CONTRACT_VIOLATION) #define GSL_CONTRACT_CHECK(type, cond) GSL_ASSUME(cond) #endifOn 9/1/2018 5:47 PM, Nick Sabalausky (Abscissa) wrote:Let's face it, the term "assert" has been poisoned by decades of ambiguity.All in all, John is very non-committal about the whole thing.He probably got tired of arguing about it :-)
Sep 09 2018
On Sunday, 9 September 2018 at 09:01:28 UTC, Ola Fosheim Grøstad wrote:Ahh, I so, so wish what you said was true. The endless debates in this forum, and many other forums across the 'net and sadly, in my own workplace, have firmly convinced me... * The terminology is indeed widespread. * and well understood across the field * to mean subtly different and incompatible things to different groups of people. ie. Yes, everybody knows the words, everybody can read the code, everybody can find somebody who agrees with his intent and meaning.... but get a large enough group together to try agree on what actions, for example, the optimiser should take that are implied by that meaning... and flames erupt. Suddenly you find people don't actually agree on the intent and meaning of the code. Communication is hard, human communication is doubly hard. I beg humanity to give up on that word "assert" and come up with others words and define explicit the intent and meaning and implications. So much pain will be avoided.Let's face it, the term "assert" has been poisoned by decades of ambiguity.There is really no ambiguity... The terminology is widespread and well understood across the field I think.
Sep 09 2018
On Sunday, 9 September 2018 at 21:20:11 UTC, John Carter wrote:ie. Yes, everybody knows the words, everybody can read the code, everybody can find somebody who agrees with his intent and meaning.... but get a large enough group together to try agree on what actions, for example, the optimiser should take that are implied by that meaning... and flames erupt.Well, it has less to do with "assert" than with how semantics are assigned to something that should never occur. But it isn't really optimal to hardcode failure semantics in the source code... Even simple semantics, like whether tests should be emitted in release builds is possibly context dependent, so not really possible to determine with any level of certainty when writing a library reused across many projects.
Sep 10 2018
On 02.09.2018 02:47, Nick Sabalausky (Abscissa) wrote:On 09/01/2018 08:44 PM, Nick Sabalausky (Abscissa) wrote:I think you misunderstood what the original post and Guillaumes disappointment was about. Walter claims that John agrees that UB on failure is the best default -release behavior for assertions. John rather explicitly states the opposite in the article. Being non-committal about whether assertions should be enabled in production or not just means that the language should provide both options. D does not. Assertions are always enabled: either they are checked or they are used as assumptions."Are Assertions Enabled in Production Code?" "This is entirely situational." "The question of whether it is better to stop or keep going when an internal bug is detected is not a straightforward one to answer."All in all, John is very non-committal about the whole thing.
Sep 05 2018
On 9/5/2018 4:55 PM, Timon Gehr wrote:John rather explicitly states the opposite in the article.I believe that his statement: "it’s not an interpretation that is universally useful" is much weaker than saying "the opposite". He did not say it was "never useful". For example, it is not universally true that airplanes never crash. But it is rare enough that we can usefully assume the next one we get on won't crash.
Sep 06 2018
On 06.09.2018 23:47, Walter Bright wrote:On 9/5/2018 4:55 PM, Timon Gehr wrote:Wait, what? From this it would follow that "UB on failing assert is never useful" is the opposite of your stance. Therefore you would think that "UB on failing assert is _sometimes_ useful". (I don't have any qualm with this, but I would note that this will not be very common, and that a per compilation unit switch is a too coarse-grained way to select asserts you want to use for optimization, and it also affects safe-ty therefore there should just be a system __assume primitive _instead_.) However, not allowing to _disable_ asserts instead of turning them into UB is only a good idea if "UB on failing assert is always useful". (I totally, utterly disagree with this and we have filled pages of newsgroup posts where you were championing this claim.) So, which is it?John rather explicitly states the opposite in the article.I believe that his statement: "it’s not an interpretation that is universally useful" is much weaker than saying "the opposite". He did not say it was "never useful". ...For example, it is not universally true that airplanes never crash. But > it is rare enough that we can usefully assume the next one we get on won't crash.So if your stance was: "Airplanes don't crash", and John were to come and write an article that said: "There are two ways to think about airplanes: 1. If they crash, you die. This is the best way to think about airplanes. 2. Another popular way to think about airplanes is that they don't crash. However, this interpretation is not universally useful. In fact, it can be dangerous if adopted by pilots or engineers." Then you would conclude: "I am very happy that John agrees with me that airplanes don't crash." ?
Sep 08 2018
On Saturday, September 1, 2018 2:15:15 PM MDT Walter Bright via Digitalmars- d wrote:https://blog.regehr.org/archives/1091 As usual, John nails it in a particularly well-written essay. "ASSERT(expr) Asserts that an expression is true. The expression may or may not be evaluated. If the expression is true, execution continues normally. If the expression is false, what happens is undefined." Note the "may or may not be evaluated." We've debated this here before. I'm rather pleased that John agrees with me on this. I.e. the optimizer can assume the expression is true and use that information to generate better code, even if the assert code generation is turned off.Personally, my concern about letting the compiler optimize based on assertions has to do with whether it violates safe. IMHO, it defeats the purpose of safe if adding an assertion can result in system code due to optimizations. I'm fine with it optimizing so long as the optimizations will not result in safe code becoming system in the case where the assertion would have failed if it were compiled in. If safe allows system optimizations than it isn't actually safe, because while we don't want assertions to ever turn out to be false, they sometimes do turn out to be false, and if they're not compiled in, it's not going to be caught. That then is obviously a bug, but at least it isn't one that's going to corrupt memory (at least if it's in safe code), but if the compiler is allowed to optimize based on the assertion to the point that the code could corrupt memory if the assertion would have failed, then that's a serious problem and a total violation of the promises made by safe. And actually, it can't add system optimizations even in system code, because that completely defeats the ability of the programmer to verify the code for safety in order to use trusted. If the compiler can add safe optimizations based on assertions, then that's fine with me (though I know that some others don't agree), but they have to be safe even when the assertion would have failed if it were compiled in. If they're ever system, then safe isn't actually safe. - Jonathan M Davis
Sep 01 2018
On Sunday, 2 September 2018 at 02:32:31 UTC, Jonathan M Davis wrote:On Saturday, September 1, 2018 2:15:15 PM MDT Walter Bright via Digitalmars- d wrote:I believe asserts are the general case of which bounds checking is a specific instance. safe code is only safe if bounds-checking is enabled for safe. void foo(int[] a) safe { a[0] = 1; } is only really guaranteed safe if a bounds check is done, because [] is a valid array for a caller to pass. void foo(int[] a) safe { assert(a.length == 1); a[0] = 1; } if asserts can be used as guarantees for the optimiser even when removed, this code is only safe when asserts are enabled (because otherwise the bounds checks would be elided as they are guaranteed to pass). So, essentially we just have to treat asserts like bounds checks and safe will work as expected. P.S. // assert debug assert(cond, msg); // assume assert(cond, msg);https://blog.regehr.org/archives/1091 As usual, John nails it in a particularly well-written essay. "ASSERT(expr) Asserts that an expression is true. The expression may or may not be evaluated. If the expression is true, execution continues normally. If the expression is false, what happens is undefined." Note the "may or may not be evaluated." We've debated this here before. I'm rather pleased that John agrees with me on this. I.e. the optimizer can assume the expression is true and use that information to generate better code, even if the assert code generation is turned off.Personally, my concern about letting the compiler optimize based on assertions has to do with whether it violates safe. IMHO, it defeats the purpose of safe if adding an assertion can result in system code due to optimizations. I'm fine with it optimizing so long as the optimizations will not result in safe code becoming system in the case where the assertion would have failed if it were compiled in. If safe allows system optimizations than it isn't actually safe, because while we don't want assertions to ever turn out to be false, they sometimes do turn out to be false, and if they're not compiled in, it's not going to be caught. That then is obviously a bug, but at least it isn't one that's going to corrupt memory (at least if it's in safe code), but if the compiler is allowed to optimize based on the assertion to the point that the code could corrupt memory if the assertion would have failed, then that's a serious problem and a total violation of the promises made by safe. And actually, it can't add system optimizations even in system code, because that completely defeats the ability of the programmer to verify the code for safety in order to use trusted. If the compiler can add safe optimizations based on assertions, then that's fine with me (though I know that some others don't agree), but they have to be safe even when the assertion would have failed if it were compiled in. If they're ever system, then safe isn't actually safe. - Jonathan M Davis
Sep 02 2018
On Sunday, September 2, 2018 1:52:34 PM MDT John Colvin via Digitalmars-d wrote:Well, if that were the intention, then -release could not remove assertions from safe code. -release does not remove bounds checking from safe code. You have to use -boundscheck=off to disable assertions in safe code (which is of course discouraged, since it makes the code not safe). So, if we were to decide that assertions had to be left in for code to stay safe, then we would have to start leaving them in in safe code when -release is used and only compile them out with a new flag specifically for compiling out assertions in safe code. And that would have pretty far-reaching effects given that it's very much understood right now that -release removes assertions. And personally, I'd probably use assertions a lot less if they were going to be left in with -release. So, while I think that that's a better approach that allowing system optimizations in safe code when assertions are removed, I can't say that I think that it's a great idea - though the folks who pretty much always want assertions enabled would probably like it (though they can already just skip -release). - Jonathan M DavisIf the compiler can add safe optimizations based on assertions, then that's fine with me (though I know that some others don't agree), but they have to be safe even when the assertion would have failed if it were compiled in. If they're ever system, then safe isn't actually safe.I believe asserts are the general case of which bounds checking is a specific instance. safe code is only safe if bounds-checking is enabled for safe. void foo(int[] a) safe { a[0] = 1; } is only really guaranteed safe if a bounds check is done, because [] is a valid array for a caller to pass.
Sep 02 2018
On Monday, 3 September 2018 at 06:26:59 UTC, Jonathan M Davis wrote:Well, if that were the intention, then -release could not remove assertions from safe code. -release does not remove bounds checking from safe code. You have to use -boundscheck=off to disable assertions in safe code (which is of course discouraged, since it makes the code not safe). So, if we were to decide that assertions had to be left in for code to stay safe, then we would have to start leaving them in in safe code when -release is used and only compile them out with a new flag specifically for compiling out assertions in safe code. And that would have pretty far-reaching effects given that it's very much understood right now that -release removes assertions. And personally, I'd probably use assertions a lot less if they were going to be left in with -release. So, while I think that that's a better approach that allowing system optimizations in safe code when assertions are removed, I can't say that I think that it's a great idea - though the folks who pretty much always want assertions enabled would probably like it (though they can already just skip -release). - Jonathan M DavisYes, the command line interface needs to make it easy and obvious to do the right thing.
Sep 03 2018
On Saturday, 1 September 2018 at 20:15:15 UTC, Walter Bright wrote:Note the "may or may not be evaluated." We've debated this here before. I'm rather pleased that John agrees with me on this.It shouldn't allow side-effects then though. https://run.dlang.io/is/P6VnYd Also a common source of bugs in C.
Sep 02 2018
On 09/01/2018 04:15 PM, Walter Bright wrote:https://blog.regehr.org/archives/1091This does make me think of one thing: Shouldn't assert expressions be required to be pure? (even if only weakly pure) Not sure how much practical problems that would create, but at least in theory it certainly sounds like the right thing.
Sep 02 2018
On Sunday, 2 September 2018 at 21:12:39 UTC, Nick Sabalausky (Abscissa) wrote:This does make me think of one thing: Shouldn't assert expressions be required to be pure? (even if only weakly pure) Not sure how much practical problems that would create, but at least in theory it certainly sounds like the right thing.Exactly. You may still catch assert(!fclose(f)) but not other non-obvious functions. Nice trick to find them in C: https://stackoverflow.com/questions/10593492/catching-assert-with-side-effects/35294344#35294344
Sep 03 2018
On 9/2/2018 2:12 PM, Nick Sabalausky (Abscissa) wrote:On 09/01/2018 04:15 PM, Walter Bright wrote:It's come up before. The trouble comes when the code doing the evaluation has side effects which are benign to the function being compiled, and these can be useful. For example, it could read a mutable global variable.https://blog.regehr.org/archives/1091This does make me think of one thing: Shouldn't assert expressions be required to be pure? (even if only weakly pure) Not sure how much practical problems that would create, but at least in theory it certainly sounds like the right thing.
Sep 05 2018
On Saturday, 1 September 2018 at 20:15:15 UTC, Walter Bright wrote:https://blog.regehr.org/archives/1091 As usual, John nails it in a particularly well-written essay. "ASSERT(expr) Asserts that an expression is true. The expression may or may not be evaluated. If the expression is true, execution continues normally. If the expression is false, what happens is undefined." Note the "may or may not be evaluated." We've debated this here before. I'm rather pleased that John agrees with me on this. I.e. the optimizer can assume the expression is true and use that information to generate better code, even if the assert code generation is turned off.I used to completely agree with your position about asserts being used for optimization purposes, until I realized that part of your position was for asserts to be used as optimization hints *even if they aren't checked*. This battle has been fought over and over, with no movement on either side, so I'll just comment that nobody what John Nails or anyone else says, my personal opinion is that you're 100% wrong on that point :-)
Sep 03 2018
On Monday, 3 September 2018 at 16:53:35 UTC, Meta wrote:This battle has been fought over and over, with no movement on either side, so I'll just comment that nobody what John Nails or anyone else says, my personal opinion is that you're 100% wrong on that point :-)Well, John Regehr seems to argue that you shouldn't use asserts for optimization even if they are turned on as the runtime might override a failed assert. «As developers, we might want to count on a certain kind of behavior when an assertion fails. For example, Linux’s BUG_ON() is defined to trigger a kernel panic. If we weaken Linux’s behavior, for example by logging an error message and continuing to execute, we could easily end up adding exploitable vulnerabilities.» So…
Sep 05 2018
On Wednesday, 5 September 2018 at 10:30:46 UTC, Ola Fosheim Grøstad wrote:On Monday, 3 September 2018 at 16:53:35 UTC, Meta wrote:I don't disagree. I think the only sane way to use asserts as an optimization guide is when the program will abort if the condition does not hold. That, to me, makes perfect sense, since you're basically telling the compiler "This condition must be true past this assertion point, because otherwise program execution will not continue past this point". You're ensuring that the condition specified in the assert is true by definition. Not having that hard guarantee but still using asserts as an optimization guide is absolutely insane, IMO.This battle has been fought over and over, with no movement on either side, so I'll just comment that nobody what John Nails or anyone else says, my personal opinion is that you're 100% wrong on that point :-)Well, John Regehr seems to argue that you shouldn't use asserts for optimization even if they are turned on as the runtime might override a failed assert. «As developers, we might want to count on a certain kind of behavior when an assertion fails. For example, Linux’s BUG_ON() is defined to trigger a kernel panic. If we weaken Linux’s behavior, for example by logging an error message and continuing to execute, we could easily end up adding exploitable vulnerabilities.» So…
Sep 05 2018
On Wed, Sep 05, 2018 at 07:35:46PM +0000, Meta via Digitalmars-d wrote: [...]I don't disagree. I think the only sane way to use asserts as an optimization guide is when the program will abort if the condition does not hold. That, to me, makes perfect sense, since you're basically telling the compiler "This condition must be true past this assertion point, because otherwise program execution will not continue past this point". You're ensuring that the condition specified in the assert is true by definition. Not having that hard guarantee but still using asserts as an optimization guide is absolutely insane, IMO.Sometimes I wonder about a new primitive called 'assume' for optimizer hints that *cannot* be (easily) verified at runtime. The current meaning of 'assert', to most people, appears to be 'abortIfFalse'. Walter's definition appears to be 'abortIfFalse' + 'assume'. This conflation has cost us endless debates on the forum, and I'm wondering if the way out is to stop conflating the two and acknowledge both as orthogonal, albeit related, primitives. T -- "Hi." "'Lo."
Sep 05 2018
On Wednesday, 5 September 2018 at 19:35:46 UTC, Meta wrote:I don't disagree. I think the only sane way to use asserts as an optimization guide is when the program will abort if the condition does not hold. That, to me, makes perfect sense, since you're basically telling the compiler "This condition must be true past this assertion point, because otherwise program execution will not continue past this point". You're ensuring that the condition specified in the assert is true by definition. Not having that hard guarantee but still using asserts as an optimization guide is absolutely insane, IMO.Yes, if you have an advanced optimizer then it becomes dangerous. Although a prover could use asserts-with-a-hint for focusing the time spent on searching for proofs. It would be way too slow to do that for all asserts, but I guess you could single out some of the easier ones that are likely to impact performance. That would be safe. There are some cases where "assume" makes sense, of course. For instance if you know that a byte-pointer will have a certain alignment then you can get the code gen to generate more efficient instructions that presume a certain alignment or if you can tell the compiler to "assume" that a region of memory is filled with zeros then maybe the optimizer can skip initialization when creating objects... And it kinda make sense to be able to autogenerate tests for such assumptions for debugging. So it would be like an assert-turned-into-assume, but very rarely used... This would be more of an expert tool for library authors and hardcore programmers than a general compiler-optimization.
Sep 05 2018
On Wednesday, 5 September 2018 at 19:35:46 UTC, Meta wrote:I think the only sane way to use asserts as an optimization guide is when the program will abort if the condition does not hold.Which is the usual behavior of assert. I'm all for using them to optimize but it's not clear how to do that. You can't just blindly turn it into assume since that may actually impede optimizations: https://llvm.org/docs/LangRef.html#llvm-assume-intrinsic
Sep 07 2018
On 09/05/2018 03:35 PM, Meta wrote:I think the only sane way to use asserts as an optimization guide is when the program will abort if the condition does not hold. That, to me, makes perfect sense, since you're basically telling the compiler "This condition must be true past this assertion point, because otherwise program execution will not continue past this point". You're ensuring that the condition specified in the assert is true by definition. Not having that hard guarantee but still using asserts as an optimization guide is absolutely insane, IMO.I'd certainly agree with this. Frankly though, I've always found `-release` itself to be a horrible thing to use, and I never go anywhere near it. It's a classic case of premature optimization, pure and simple - and a dangerous one at that. IMO the only time an assert should be omitted (note: *an* assert, none of this module-level granularity stuff), even in release mode, is when you can verify that leaving the assert in would be prohibitively expensive: For example, frequent integrity checks on large trees, or bounds-checking an inner-loop of a performance-critical codepath. Removing an assert in release mode is exactly the same as declaring "This part can't ever fail, so let's not worry about 'What happens if it does fail?'" (if you're THAT certain, why did you write the assert there in the first place???). TBH, I'm very surprised that Walter would ever be in favor of it.
Sep 08 2018
On Saturday, September 8, 2018 5:31:43 PM MDT Nick Sabalausky (Abscissa) via Digitalmars-d wrote:On 09/05/2018 03:35 PM, Meta wrote:I think that it's all about how you look at it. If you look at assertions as a way to abort your program because things are so broken that it's too dangerous to continue, then yeah, removing them is dangerous. However, if you look at them purely as a debugging tool to help you catch problems during develepment, that it's no more dangerous to remove assertions and have the code continue if they would have failed than it is for any other part of the program to be wrong and continue to operate. There's nothing special about the code being wrong when an assertion fails except that it's a case where you put an actual test for it. That code is broken or not regardless of whether the assertion is actually there. The assertion is just helping to catch the bug. I think that that it's this duality of thinking here that's causing a lot of the problems. Assertions are usually presented as a way to catch bugs during development (and thus will be removed in production) and _not_ as a way to catch errors severe enough to abort the program in production. And so a lot of programmers are going to use them purely as a debugging tool. So, for assertions to then be used to kill the program in production arguably doesn't match what they were intended for at all, and when you're adding assertions with the understanding that they're going to be removed in production, you're a lot more likely to do stuff like use an assertion to verify that sort sorted a list correctly, which would be insane to do in production, whereas if you were using assertions specifically to indicate that the program _must_ abort if the condition isn't true - even in production - then you're going to be thinking completely differently about what you test in assertions. IIRC, Weka has different types of assertions to differentiate between these two approaches - one for the cases which absolutely must not happen in production, and one that's purely for catching problems during developement. And really, I think that that's probably the right approach. For many programs, leaving assertions in during production is just going to needlessly slow the program down, and if the developers know that an assertion is going to be left in production, they're a lot less likely to use assertions. On the other hand, there are definitely cases where testing a conditition is critical enough that you want that test to always be in the code and for it to abort on failure even in production. So, maybe what we should do here is take a page from Weka's playbook and add a function that does something like check a condition and then assert(0) if it's false and not try to say that assertions should always be left in production. Sure, someone can choose to not use -relase and leave them in, but that's often not how assertions are actually used (e.g. last time I checked std.algorithm's sort really does check that the range is sorted with an assertion). - Jonathan M DavisI think the only sane way to use asserts as an optimization guide is when the program will abort if the condition does not hold. That, to me, makes perfect sense, since you're basically telling the compiler "This condition must be true past this assertion point, because otherwise program execution will not continue past this point". You're ensuring that the condition specified in the assert is true by definition. Not having that hard guarantee but still using asserts as an optimization guide is absolutely insane, IMO.I'd certainly agree with this. Frankly though, I've always found `-release` itself to be a horrible thing to use, and I never go anywhere near it. It's a classic case of premature optimization, pure and simple - and a dangerous one at that. IMO the only time an assert should be omitted (note: *an* assert, none of this module-level granularity stuff), even in release mode, is when you can verify that leaving the assert in would be prohibitively expensive: For example, frequent integrity checks on large trees, or bounds-checking an inner-loop of a performance-critical codepath. Removing an assert in release mode is exactly the same as declaring "This part can't ever fail, so let's not worry about 'What happens if it does fail?'" (if you're THAT certain, why did you write the assert there in the first place???). TBH, I'm very surprised that Walter would ever be in favor of it.
Sep 08 2018
On Sunday, 9 September 2018 at 06:27:52 UTC, Jonathan M Davis wrote:So, maybe what we should do here is take a page from Weka's playbook and add a function that does something like check a condition and then assert(0) if it's false and not try to say that assertions should always be left in production.That's the easy solution, but in real world development things get more complicated. Say, if you develop a game maybe you want no asserts in your render code, but as many asserts as possible in your game logic code... It would make sense to defer some way of control to the calling context. Especially with templated functions in a very generic library that is used across the entire program.
Sep 09 2018
On Saturday, 1 September 2018 at 20:15:15 UTC, Walter Bright wrote:Note the "may or may not be evaluated." We've debated this here before. I'm rather pleased that John agrees with me on this. I.e. the optimizer can assume the expression is true and use that information to generate better code, even if the assert code generation is turned off.Is the part about the optimizer true in D's case? Or is this just a theoretical advantage to using asserts that are not evaluated in production code but left in?
Sep 05 2018
On Wed, Sep 05, 2018 at 03:59:06PM +0000, Michael via Digitalmars-d wrote:On Saturday, 1 September 2018 at 20:15:15 UTC, Walter Bright wrote:AFAIK, no optimizer currently actually takes advantage of asserts in this way. But Walter has stated that this was his intention all along when he made asserts a part of the language (as opposed to, e.g., a macro / standard library call in C). However, whenever he talks about this, there's always a big controversy about potential pitfalls, and opinions are divided on this issue. T -- A linguistics professor was lecturing to his class one day. "In English," he said, "A double negative forms a positive. In some languages, though, such as Russian, a double negative is still a negative. However, there is no language wherein a double positive can form a negative." A voice from the back of the room piped up, "Yeah, yeah."Note the "may or may not be evaluated." We've debated this here before. I'm rather pleased that John agrees with me on this. I.e. the optimizer can assume the expression is true and use that information to generate better code, even if the assert code generation is turned off.Is the part about the optimizer true in D's case? Or is this just a theoretical advantage to using asserts that are not evaluated in production code but left in?
Sep 05 2018
On 01.09.2018 22:15, Walter Bright wrote:https://blog.regehr.org/archives/1091 As usual, John nails it in a particularly well-written essay. "ASSERT(expr) Asserts that an expression is true. The expression may or may not be evaluated. If the expression is true, execution continues normally. If the expression is false, what happens is undefined." Note the "may or may not be evaluated." We've debated this here before. I'm rather pleased that John agrees with me on this.He does not! John gives two definitions. The first definition is the one I want, and he calls it _the best definition_. (I.e., all other definitions are inferior.)I.e. the optimizer can assume the expression is true and use that information to generate better code, even if the assert code generation is turned off.The definition you quoted is the /alternative/ definition. He does not call it the best definition, and even explains that it can be dangerous. He says "it’s not an interpretation that is universally useful". (!) I don't understand how you can conclude from this that John's view is that this should be the default -release behavior of assertions.
Sep 05 2018
On Sun, Sep 09, 2018 at 12:27:52AM -0600, Jonathan M Davis via Digitalmars-d wrote: [...]IIRC, Weka has different types of assertions to differentiate between these two approaches - one for the cases which absolutely must not happen in production, and one that's purely for catching problems during developement. And really, I think that that's probably the right approach.[...] On Sun, Sep 09, 2018 at 09:20:11PM +0000, John Carter via Digitalmars-d wrote: [...][...]Let's face it, the term "assert" has been poisoned by decades of ambiguity.I beg humanity to give up on that word "assert" and come up with others words and define explicit the intent and meaning and implications. So much pain will be avoided.Indeed. D already distinguishes between assert (for catching programming errors) and enforce (for catching runtime conditions like bad user input). It's high time we distinguished between the various flavors of assert, preferably with new words to avoid the baggage that has accumulated around 'assert'. I propose: - 'assume': aborts on false condition in debug builds, not checked in release builds, used as optimizer hint; - 'insist': aborts on false condition in debug builds, aborts on false condition in release builds, used as optimizer hint; - 'uphold': aborts on false condition in debug builds, aborts on false condition in release builds, NOT used as optimizer hint; - 'allege': logs error and aborts on false condition in debug builds, logs error and continues on false condition in release builds, NOT used as optimizer hint; T -- You are only young once, but you can stay immature indefinitely. -- azephrahel
Sep 10 2018
On Monday, 10 September 2018 at 19:44:22 UTC, H. S. Teoh wrote:It's high time we distinguished between the various flavors of assert, preferably with new words to avoid the baggage that has accumulated around 'assert'.Perhaps we can take some cues from Vigil, the eternally morally vigilant programming language, and use 'implore' for preconditions (aborts on new strict mode, throws by default) and 'swear' for other contracts?
Sep 10 2018