July 31, 2014
Walter Bright:

> I'd like to see what you are saying is different in a real example.

(The problem is that your have defined your own idea, so what I can show you will look meaningless or not comformant to your own definition. So this discussion is going nowhere. And my original topic drowns in this assume/assert debate that is off-topic.)


In the case of assume:


int max(in int x, in int y) {
    assume(x > y);
    return (x > y) ? x : y;
}

The optimizer is free to replace that code with this, even in debug builds:

int max(in int x, in int y) {
    return x;
}



In the case of assert:

int max(in int x, in int y) {
    assert(x > y);
    return (x > y) ? x : y;
}


In debug builds gets rewritten as:

int max(in int x, in int y) {
    if (x <= y)
        throw new AssertError("...");
    return x;
}


And in release builds gets rewritten as:

int max(in int x, in int y) {
    return (x > y) ? x : y;
}


Bye,
bearophile
July 31, 2014
> In debug builds gets rewritten as:
>
> int max(in int x, in int y) {
>     if (x <= y)
>         throw new AssertError("...");
>     return x;
> }


Sorry, I meant:

In debug builds gets rewritten as:

int max(in int x, in int y) {
    if (x <= y)
        throw new AssertError("...");
    return (x > y) ? x : y;
}


Bye,
bearophile
July 31, 2014
On Thursday, 31 July 2014 at 08:36:12 UTC, John Colvin wrote:
> Wait what? Now I'm confused.
>
> x < y is guaranteed at point B (the assert).
>
> x and y are unchanged between point A (the enforce) and point B.
>
> Therefore, x < y is guaranteed at point A

That's not true. If x and y didn't follow x < y, then point B would never execute (enforce would throw an exception and point B would never have executed. So it's entirely possible for x >= y before point A, but never after point A. The enforce shouldn't ever be removed (but the assert technically can be without changing the behavior of the code).

The same logic holds for the other way,

    assert(x < y);
    enforce(x < y);

The enforce is redundant and can be removed there.
July 31, 2014
On Thursday, 31 July 2014 at 10:14:06 UTC, Marc Schütz wrote:
> On Thursday, 31 July 2014 at 08:23:44 UTC, Daniel Murphy wrote:
>> "Daniel Murphy"  wrote in message news:lrct2d$1me8$1@digitalmars.com...
>>
>>> > Wait, what? I thought the whole point of enforce is that it will *not*
>>> > be removed by the compiler, no matter what?
>>>
>>> No, the compiler is free to remove it if it can prove it will never be triggered.  eg if the condition is checking a ubyte < 1000.  If the assert in that example is never false, then the enforce is dead code.
>>
>> Actually, thinking about this some more...
>>
>> In this program the enforce can be removed
>>
>> assert(x < y);
>> enforce(x < y);
>>
>> But not in this one:
>>
>> enforce(x < y);
>> assert(x < y);
>>
>> because the compiler does need to take control flow into account when applying the information in the assert.  In this case the assert does not actually give the compiler any new information.
>
> No, if assert means "I promise that x < y where assert() is called", then "x < y" also holds when "enforce()" is called, because x and y cannot have changed between the two calls.

Ok, I take that back.

http://forum.dlang.org/thread/jrxrmcmeksxwlyuitzqp@forum.dlang.org?page=26#post-wzzayaevjsulxyuhlxzh:40forum.dlang.org
July 31, 2014
Am 31.07.2014 04:53, schrieb Walter Bright:
> On 7/30/2014 6:38 PM, Daniel Gibson wrote:
>> I'm in favor of a "harmless" assert().
>> In C(++) I sometimes use things like
>>
>> assert(x != NULL);
>>
>> if(x != NULL) {
>>      x->foo = 42;
>>      // ...
>> }
>>
>> I have that assertion to hopefully find bugs during development and
>> fix them.
>> However, no program is bug free and so it's totally possible that x
>> *is* NULL in
>> some circumstance in the wild (in a "release" mode binary), so I want
>> to make
>> sure it doesn't explode if that happens but handle the problem more
>> gracefully.
>>
>> It would be rather unfortunate if the compiler removed that second
>> check in
>> release mode because the assertion made it assume that x can't be NULL.
>
> Your code is doomed to having problems using assert this way.
>
> The behavior you desire here is easily handled by creating your own
> template to exhibit it. See the implementation of enforce() for how to
> do it.
>

Now that's a bit surprising to me, as you wrote in the other thread:
> 7. using enforce() to check for program bugs is utterly wrong.
> enforce() is a library creation, the core language does not recognize
> it."

Until now (being mostly a C/C++ guy), I saw assertions as a way to find bugs during development/testing that is completely eliminated in release mode (so I might still want to handle the asserted conditions gracefully there) - and it seems like I'm not alone with that view.

Because (in C/C++) assertions just vanish when NDEBUG isn't defined, it would never occur to me that they have any influence on such (release mode) builds.
Doing optimizations on this would just lead to frustration, like several kinds of optimizations recently have (e.g. this "compiler will remove bzero() on memory that isn't used afterwards" bullshit).

Cheers,
Daniel
July 31, 2014
On Thursday, 31 July 2014 at 07:00:01 UTC, Walter Bright wrote:
> On 7/30/2014 10:49 PM, Tofu Ninja wrote:
>> On Thursday, 31 July 2014 at 05:05:33 UTC, Walter Bright wrote:
>>> On 7/30/2014 8:09 PM, Tofu Ninja wrote:
>>>> When is the appropriate time to use an assert? If an assert
>>>> should not be used on input, then any thing that can't be
>>>> statically known is considered an input and anything that is
>>>> derived from an input is also an input... so when can we use an
>>>> assert? The only things left it seems are things know at compile
>>>> time and at that point what is the the point of having assert
>>>> when we have static assert...
>>>
>>> Asserts are used to verify the logic of your code is correct:
>>>
>>>   x = y + y;
>>>   assert(x == 2 * y);
>>
>> If x and y are floats and y is nan then that assert will fail.....
>> That assert is implicitly verifying that the input y is not nan,
>> that is a misuse of assert by your definition.
>
> If it pleases you, prepend int x,y; to the snippet.
>
>
>> Any assert made on a piece of data that is derived from inputs is
>> verifying some aspect of that input, which is a misuse of assert
>> according to the current definition. So I still state that
>> according to current definitions, assert should only be used on
>> things that are known at compile time. What is the use of that?
>
> For example, you can have a sort function, and then at the end assert that the output of the function is sorted.

But that is verifying that the input is sort-able....

All I am saying is that the idea that assert should not be used to verify input makes no sense at all. Every program takes in input and once a little bit is in, anything derived from that input is also input.

...

Also this thread has made me firmly never want to trust assert again... I have actually been going though my projects and removing them now because I don't trust them any more...
July 31, 2014
On Thursday, 31 July 2014 at 10:14:06 UTC, Marc Schütz wrote:
> On Thursday, 31 July 2014 at 08:23:44 UTC, Daniel Murphy wrote:
>> "Daniel Murphy"  wrote in message news:lrct2d$1me8$1@digitalmars.com...
>>
>>> > Wait, what? I thought the whole point of enforce is that it will *not*
>>> > be removed by the compiler, no matter what?
>>>
>>> No, the compiler is free to remove it if it can prove it will never be triggered.  eg if the condition is checking a ubyte < 1000.  If the assert in that example is never false, then the enforce is dead code.
>>
>> Actually, thinking about this some more...
>>
>> In this program the enforce can be removed
>>
>> assert(x < y);
>> enforce(x < y);
>>
>> But not in this one:
>>
>> enforce(x < y);
>> assert(x < y);
>>
>> because the compiler does need to take control flow into account when applying the information in the assert.  In this case the assert does not actually give the compiler any new information.
>
> No, if assert means "I promise that x < y where assert() is called", then "x < y" also holds when "enforce()" is called, because x and y cannot have changed between the two calls.

I think this is the biggest problem with optimizing whilst removing the check. It seems like if you remove the check and assume that the check was true then you get really wonky stuff like checks before the assert being removed.

One solution that would still provide some optimization benefits is to make the optimizations as if the check is still their. Meaning that only things after the assert could be optimized based on the contents of the assert.

I think that is an extension of what Daniel is saying. The assert optimization needs to take into account control flow, but It needs to take into account its own control flow as well(even if the control flow is not actually inserted).

so...

enforce(x);
assert(x);

would not remove the enforce.... because the x would only be known to be true after the assert because of the check in assert, even if the check is not added it would optimize as if it was added.
July 31, 2014
On 7/31/2014 7:51 AM, Tofu Ninja wrote:
>> For example, you can have a sort function, and then at the end assert that the
>> output of the function is sorted.
>
> But that is verifying that the input is sort-able....

Integers are sortable, period. That is not "input".


> All I am saying is that the idea that assert should not be used to verify input
> makes no sense at all. Every program takes in input and once a little bit is in,
> anything derived from that input is also input.

You're denying the existence of mathematical identities applied to symbolic math.


> Also this thread has made me firmly never want to trust assert again... I have
> actually been going though my projects and removing them now because I don't
> trust them any more...

I suggest revisiting the notion of program logic correctness vs input verification.
July 31, 2014
On 7/31/2014 6:37 AM, Daniel Gibson wrote:
>> The behavior you desire here is easily handled by creating your own
>> template to exhibit it. See the implementation of enforce() for how to
>> do it.
>>
>
> Now that's a bit surprising to me, as you wrote in the other thread:
>  > 7. using enforce() to check for program bugs is utterly wrong.
>  > enforce() is a library creation, the core language does not recognize
>  > it."
>
> Until now (being mostly a C/C++ guy), I saw assertions as a way to find bugs
> during development/testing that is completely eliminated in release mode (so I
> might still want to handle the asserted conditions gracefully there) - and it
> seems like I'm not alone with that view.

The assert will not cause code to be generated to test the assertion at runtime with -release. But the assert must still be valid, and since it is valid, the optimizer should be able to take advantage of it.

assert is not meant to be used as "I want my program to be valid even if the assert is false".

> Because (in C/C++) assertions just vanish when NDEBUG isn't defined, it would
> never occur to me that they have any influence on such (release mode) builds.
> Doing optimizations on this would just lead to frustration, like several kinds
> of optimizations recently have (e.g. this "compiler will remove bzero() on
> memory that isn't used afterwards" bullshit).

That's the way assert in C/C++ conventionally worked. But this is changing. Bearophile's reference made it clear that Microsoft C++ 2013 has already changed, and I've seen discussions for doing the same with gcc and clang.

In fact, the whole reason assert is a core language feature rather than a library notion is I was anticipating making use of assert for optimization hints.
July 31, 2014
Am 31.07.2014 21:19, schrieb Walter Bright:
> That's the way assert in C/C++ conventionally worked. But this is
> changing. Bearophile's reference made it clear that Microsoft C++ 2013
> has already changed, and I've seen discussions for doing the same with
> gcc and clang.

This will break so much code :-/

>
> In fact, the whole reason assert is a core language feature rather than
> a library notion is I was anticipating making use of assert for
> optimization hints.

So why is this not documented?
The assert documentation isn't even clear on when an AssertError is thrown and when execution is halted (http://dlang.org/contracts.html doesn't mention halt at all).
And it says "When compiling for release, the assert code is not generated." - if you implemented assert like this so the optimizer can assume the assertion to be true even when "assert code is not generated" this is certainly something developers should be very aware of - and not once you actually implement that optimization, but from day one, so they can use assert accordingly!

This thread however shows that many D users (who probably have more D experience than myself) are not aware that assert() may influence optimization and would prefer to have separate syntax to tell the optimizer what values he can expect.

Cheers,
Daniel