September 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."
September 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.

September 06, 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.
September 06, 2018
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.
September 06, 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.
September 07, 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
September 08, 2018
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." ?
September 08, 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.
September 09, 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 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



September 09, 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:
>> 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.