www.digitalmars.com         C & C++   DMDScript  

digitalmars.D - John Regehr on "Use of Assertions"

reply Walter Bright <newshound2 digitalmars.com> writes:
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
next sibling parent reply Guillaume Boucher <guillaume.boucher.d outlook.com> writes:
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
parent reply Walter Bright <newshound2 digitalmars.com> writes:
On 9/1/2018 3:23 PM, Guillaume Boucher wrote:
 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.
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.
 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*.
I don't interpret it that way. Disabling runtime assert checking turns them into assumes. John is implying asserts should never be disabled.
Sep 01 2018
parent reply "Nick Sabalausky (Abscissa)" <SeeWebsiteToContactMe semitwist.com> writes:
On 09/01/2018 07:54 PM, Walter Bright wrote:
 On 9/1/2018 3:23 PM, Guillaume Boucher wrote:
 On Saturday, 1 September 2018 at 20:15:15 UTC, Walter Bright wrote:
 
 [John agrees with me.]
[No, he doesn't.]
[Yea-huh, he does.]
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."
Sep 01 2018
next sibling parent "Nick Sabalausky (Abscissa)" <SeeWebsiteToContactMe semitwist.com> writes:
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
prev sibling parent reply "Nick Sabalausky (Abscissa)" <SeeWebsiteToContactMe semitwist.com> writes:
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
next sibling parent reply Walter Bright <newshound2 digitalmars.com> writes:
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
parent reply John Carter <john.carter taitradio.com> writes:
On Sunday, 2 September 2018 at 01:55:53 UTC, Walter Bright wrote:
 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 :-)
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.
Sep 09 2018
parent reply Ola Fosheim =?UTF-8?B?R3LDuHN0YWQ=?= <ola.fosheim.grostad gmail.com> writes:
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:
 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 :-)
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. "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) #endif
Sep 09 2018
parent reply John Carter <john.carter taitradio.com> writes:
On Sunday, 9 September 2018 at 09:01:28 UTC, Ola Fosheim Grøstad 
wrote:

 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.
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.
Sep 09 2018
parent Ola Fosheim =?UTF-8?B?R3LDuHN0YWQ=?= <ola.fosheim.grostad gmail.com> writes:
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
prev sibling parent reply Timon Gehr <timon.gehr gmx.ch> writes:
On 02.09.2018 02:47, Nick Sabalausky (Abscissa) wrote:
 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.
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.
Sep 05 2018
parent reply Walter Bright <newshound2 digitalmars.com> writes:
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
parent Timon Gehr <timon.gehr gmx.ch> writes:
On 06.09.2018 23:47, Walter Bright wrote:
 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". ...
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?
 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
prev sibling next sibling parent reply Jonathan M Davis <newsgroup.d jmdavisprog.com> writes:
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
parent reply John Colvin <john.loughran.colvin gmail.com> writes:
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:
 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
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);
Sep 02 2018
parent reply Jonathan M Davis <newsgroup.d jmdavisprog.com> writes:
On Sunday, September 2, 2018 1:52:34 PM MDT John Colvin via Digitalmars-d 
wrote:
 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.
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.
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 Davis
Sep 02 2018
parent John Colvin <john.loughran.colvin gmail.com> writes:
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 Davis
Yes, the command line interface needs to make it easy and obvious to do the right thing.
Sep 03 2018
prev sibling next sibling parent Trass3r <un known.com> writes:
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
prev sibling next sibling parent reply "Nick Sabalausky (Abscissa)" <SeeWebsiteToContactMe semitwist.com> writes:
On 09/01/2018 04:15 PM, Walter Bright wrote:
 https://blog.regehr.org/archives/1091
 
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.
Sep 02 2018
next sibling parent Trass3r <un known.com> writes:
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
prev sibling parent Walter Bright <newshound2 digitalmars.com> writes:
On 9/2/2018 2:12 PM, Nick Sabalausky (Abscissa) wrote:
 On 09/01/2018 04:15 PM, Walter Bright wrote:
 https://blog.regehr.org/archives/1091
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.
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.
Sep 05 2018
prev sibling next sibling parent reply Meta <jared771 gmail.com> writes:
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
parent reply Ola Fosheim =?UTF-8?B?R3LDuHN0YWQ=?= <ola.fosheim.grostad gmail.com> writes:
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
parent reply Meta <jared771 gmail.com> writes:
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:
 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…
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.
Sep 05 2018
next sibling parent "H. S. Teoh" <hsteoh quickfur.ath.cx> writes:
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
prev sibling next sibling parent Ola Fosheim =?UTF-8?B?R3LDuHN0YWQ=?= <ola.fosheim.grostad gmail.com> writes:
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
prev sibling next sibling parent Trass3r <un known.com> writes:
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
prev sibling parent reply "Nick Sabalausky (Abscissa)" <SeeWebsiteToContactMe semitwist.com> writes:
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
parent reply Jonathan M Davis <newsgroup.d jmdavisprog.com> writes:
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 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.
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 Davis
Sep 08 2018
parent Ola Fosheim =?UTF-8?B?R3LDuHN0YWQ=?= <ola.fosheim.grostad gmail.com> writes:
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
prev sibling next sibling parent reply Michael <michael toohuman.io> writes:
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
parent "H. S. Teoh" <hsteoh quickfur.ath.cx> writes:
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:
 
 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?
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."
Sep 05 2018
prev sibling next sibling parent Timon Gehr <timon.gehr gmx.ch> writes:
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
prev sibling parent reply "H. S. Teoh" <hsteoh quickfur.ath.cx> writes:
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
parent Neia Neutuladh <neia ikeran.org> writes:
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