July 31, 2014
"Daniel Gibson"  wrote in message news:lrdnri$2fge$1@digitalmars.com...

> One could write a memset_s oneself.. that does a memset, reads the data and writes a char of it or something to a global variable (hoping that the compiler won't optimize that to "just set that variable to 0").

Some compilers will do exactly that optimization.

> The thing is: I don't want a compiler to remove code I wrote just because it "thinks" it's superfluous.
> It could tell me about it as a warning, but it shouldn't just silently do it. If removing code makes my code faster, I can do it myself.

No you don't, no you can't.  You are using an optimizer because writing it in the perfectly precise, perfectly fast way makes your code unmaintainable. You want the optimizer to delete all those never-read initializations, drop all those temporary variables, and turn your multiplies into shifts and additions.

If you didn't, you wouldn't be using an optimizer. 

July 31, 2014
On Thursday, 31 July 2014 at 17:10:27 UTC, H. S. Teoh via Digitalmars-d wrote:
> On Thu, Jul 31, 2014 at 02:05:29AM +0000, Tofu Ninja via Digitalmars-d wrote:
>> On Wednesday, 30 July 2014 at 22:01:23 UTC, Walter Bright wrote:
>> 
>> >3. Use of assert to validate input is utterly wrong and will not be
>> >supported. Use such constructs at your own risk.
>> 
>> When exactly is it 'ok' to use assert then?
>> 
>> If asserts are not allowed to be used to verify inputs.... then by
>> extension, they can not be used to verify any derivative of an input.
>
> No that doesn't make sense. The idea behind input sanitization is that
> user-facing APIs receive arbitrary, unverified input from outside, and
> before you use that data, you scrub it. After scrubbing it, it's
> perfectly OK to use assert to verify its validity -- because if it's
> still invalid, there's a bug in your scrubbing algorithm. The scrubbed
> input *is* a derivative of the input, but you can't say that you can't
> use assert on it!
>
> (And if you *don't* scrub your data before using it, your design is
> flawed and should be fixed.)
>
>
>> So by that definition, asserts are only ok to use on any thing known
>> at compile time... that makes them utterly useless....
>
> Your definition is wrong. ;-) The idea behind asserts is that you're
> verifying *program logic*, not checking arbitrary input data. If you
> have an algorithm that computes a square root, for example, you'd use an
> assert to verify that the square of the result equals the input --
> because if not, that means something has gone wrong with your square
> root algorithm. But you shouldn't use an assert to verify that the input
> to the square root algorithm is a valid numerical string -- because the
> user could have typed "abc" instead of a number. Rather, you should
> scrub the user input and throw an exception when the input is invalid.
>
> After scrubbing, however, it's perfectly valid to assert that the input
> must be a valid number -- because if not, it means the *logic* in your
> scrubbing algorithm is flawed (perhaps it missed a corner case).
>
> It's true, however, that this simple idea is not always so simple in
> practice. One has to draw a line between "user input" and "internal
> state" somewhere, and it's not always obvious where that line falls. For
> example, viewed as a whole, the entire software application may be
> considered a system that takes input from outside, so "user input" means
> things like keystrokes, mouse movements, etc.. But internally, the
> system may consist of multiple components, and when data is passed
> between components, should they be treated as "internal state" or "user
> input"? Should library APIs treat application input as "external input"
> and vet it before use, or is it OK to use assert to enforce(!) the
> validity of data passed internally between the application's components?
> It's not always easy to decide, and sometimes judgment calls have to be
> made.
>
>
> T

With that logic(and the proposed optimizations that this whole thing is about), weird stuff like this happens...

void foo(int x)
{
    if(x != 0) throw ...;
    assert(x == 0);
}

The if check could be removed because assert will be assumed to always be true in release... so x could never not equal 0.... the assert just nuked my scrubbing logic...
July 31, 2014
Am 31.07.2014 18:29, schrieb Andrei Alexandrescu:
> On 7/31/14, 8:37 AM, Daniel Gibson wrote:
>> When I tell it to write something, I want it to do that, even if it
>> might look like nonsense (if anything, it could create a warning).
>
> I'm afraid those days are long gone by now. -- Andrei

At least for C..
It sucks not to be able to predict the behavior of sane-looking code without knowing the language standard in all details by heart.

I'd prefer if D  only did optimizations that are safe and don't change the behavior of the code and thus was less painful to use than C and C++ that need deep understanding of complicated standards to get right ("the last thing D needs is someone like Scott Meyers"?)

Examples for eliminations that I'd consider safe:
* if something is checked twice (e.g. due to inlining) it's okay to only keep the first check
* if a variable is certainly not read before the first assignment, the standard initialization could be optimized away.. same for multiple assignments without reads in between, *but*
 - that would still look strange in a debugger when you'd expect another value
 - don't we have int x = void; to prevent default initialization?
* turning multiplies into shifts and additions is totally fine if it does not change the behavior, even in corner cases.
* optimizing out variables

It's a major PITA to debug problems that only happen in release builds.

Cheers,
Daniel
July 31, 2014
On Thursday, 31 July 2014 at 17:40:45 UTC, Daniel Gibson wrote:
> Am 31.07.2014 18:29, schrieb Andrei Alexandrescu:
>> On 7/31/14, 8:37 AM, Daniel Gibson wrote:
>>> When I tell it to write something, I want it to do that, even if it
>>> might look like nonsense (if anything, it could create a warning).
>>
>> I'm afraid those days are long gone by now. -- Andrei
>
> At least for C..
> It sucks not to be able to predict the behavior of sane-looking code without knowing the language standard in all details by heart.
>
> I'd prefer if D  only did optimizations that are safe and don't change the behavior of the code and thus was less painful to use than C and C++ that need deep understanding of complicated standards to get right ("the last thing D needs is someone like Scott Meyers"?)
>
> Examples for eliminations that I'd consider safe:
> * if something is checked twice (e.g. due to inlining) it's okay to only keep the first check
> * if a variable is certainly not read before the first assignment, the standard initialization could be optimized away.. same for multiple assignments without reads in between, *but*
>  - that would still look strange in a debugger when you'd expect another value
>  - don't we have int x = void; to prevent default initialization?
> * turning multiplies into shifts and additions is totally fine if it does not change the behavior, even in corner cases.
> * optimizing out variables
>
> It's a major PITA to debug problems that only happen in release builds.
>
> Cheers,
> Daniel

I believe gdc has the full suite of gcc optimiser flags available. You don't need to just slap -O3 on and then complain about the changes it makes, you can choose with a reasonable amount of precision which optimisations you do/don't want done.
July 31, 2014
"Tofu Ninja"  wrote in message news:mhhtxjlrvtqhzztxidbe@forum.dlang.org...

> With that logic(and the proposed optimizations that this whole thing is about), weird stuff like this happens...
>
> void foo(int x)
> {
>      if(x != 0) throw ...;
>      assert(x == 0);
> }
>
> The if check could be removed because assert will be assumed to always be true in release... so x could never not equal 0.... the assert just nuked my scrubbing logic...

The if can't be removed - and it's fairly easy to see why.  In the control flow path that contains the assert, the compiler is _already_ sure that x == 0.  The assert adds no new information.

The assumption the compiler can make is "if the program got to here, this condition must be true".  The qualification is extremely important.

The corner case is "assert(0)".  It means "if the program got to here, the impossible has happened."

So with this:

void foo(int x)
{
   if(x != 0) throw ...;
   assert(0);
}

the compiler doesn't have to bother checking x at all. 

July 31, 2014
On 7/31/14, 4:37 AM, Walter Bright wrote:
> On 7/30/2014 4:05 PM, Ary Borenszweig wrote:
>> On 7/30/14, 7:01 PM, Walter Bright wrote:
>>> I'd like to sum up my position and intent on all this.
>>>
>>> 7. using enforce() to check for program bugs is utterly wrong. enforce()
>>> is a library creation, the core language does not recognize it.
>>
>> What do you suggest to use to check program bugs?
>
> assert()

Then you are potentially releasing programs with bugs that are of undefined behavior, instead of halting the program immediately.
July 31, 2014
On 7/31/2014 4:28 AM, David Bregman wrote:
> Sigh. Of course you can assume the condition after a runtime check has been
> inserted. You just showed that
>
> assert(x); assume(x);
>
> is semantically equivalent to
> assert(x);
>
> as long as the runtime check is not elided. (no -release)

No. I showed that you cannot have an assert without the assume. That makes them equivalent that direction.

For the other direction, adding in a runtime check for an assume is going to be expected of an implementation. And, in fact, since the runtime check won't change the semantics if the assume is correct, they are equivalent.

I.e. for practical purposes, they are the same thing. You can't have one without the other.


> The code generated by one will be different than the code generated by the
> other, that is because they are functionally different. This is really
> indisputable..

Oh, I dispute it very much!


> But you still want to assert to become assume in release mode? How
> will you handle the safety issue?

I don't know yet.


> So what?

It came up in the thread about assume vs assert. I assumed (!) it mattered to you.

July 31, 2014
On 7/31/2014 3:24 AM, ponce wrote:
> On Thursday, 31 July 2014 at 09:13:53 UTC, Walter Bright wrote:
>> On 7/31/2014 1:23 AM, Daniel Murphy wrote:
>>> "Walter Bright"  wrote in message news:lrbpvj$mih$1@digitalmars.com...
>>>
>>>> 5. assert(0); is equivalent to a halt, and the compiler won't remove it.
>>>
>>> This is not the same definition the spec gives.  The spec says assert(0) can be
>>> treated as unreachable, and the compiler is allowed to optimize accordingly.
>>
>> It says more than that:
>>
>> "The expression assert(0) is a special case; it signifies that it is
>> unreachable code. Either AssertError is thrown at runtime if it is reachable,
>> or the execution is halted (on the x86 processor, a HLT instruction can be
>> used to halt execution). The optimization and code generation phases of
>> compilation may assume that it is unreachable code."
>>
>>   -- http://dlang.org/expression.html#AssertExpression
>
> You said "the compiler won't remove it".

Right, and it doesn't.

> http://dlang.org/expression.html#AssertExpression says: "The optimization and
> code generation phases of compilation may assume that it is unreachable code."
>
> Who is right?

It means if the control flow does actually get there, a HALT is executed.

July 31, 2014
On 07/31/2014 09:03 PM, Walter Bright wrote:
> On 7/31/2014 3:24 AM, ponce wrote:
>> On Thursday, 31 July 2014 at 09:13:53 UTC, Walter Bright wrote:
>>> On 7/31/2014 1:23 AM, Daniel Murphy wrote:
>>>> "Walter Bright"  wrote in message news:lrbpvj$mih$1@digitalmars.com...
>>>>
>>>>> 5. assert(0); is equivalent to a halt, and the compiler won't
>>>>> remove it.
>>>>
>>>> This is not the same definition the spec gives.  The spec says
>>>> assert(0) can be
>>>> treated as unreachable, and the compiler is allowed to optimize
>>>> accordingly.
>>>
>>> It says more than that:
>>>
>>> "The expression assert(0) is a special case; it signifies that it is
>>> unreachable code. Either AssertError is thrown at runtime if it is
>>> reachable,
>>> or the execution is halted (on the x86 processor, a HLT instruction
>>> can be
>>> used to halt execution). The optimization and code generation phases of
>>> compilation may assume that it is unreachable code."
>>>
>>>   -- http://dlang.org/expression.html#AssertExpression
>>
>> You said "the compiler won't remove it".
>
> Right, and it doesn't.
>
>> http://dlang.org/expression.html#AssertExpression says: "The
>> optimization and
>> code generation phases of compilation may assume that it is
>> unreachable code."
>>
>> Who is right?
>
> It means if the control flow does actually get there, a HALT is executed.
>

And assuming control flow does not actually get there?
July 31, 2014
On Thursday, 31 July 2014 at 13:10:58 UTC, Kagamin wrote:
> On Thursday, 31 July 2014 at 06:57:15 UTC, Walter Bright wrote:
>> For LinearCongruentialEngine() and initialize(), passing invalid arguments are programming bugs, and so they should be asserting.
>
> Isn't phobos compiled in release mode? And since those asserts are never compiled, what purpose do they serve?

The whole type is templated, so the assertions will be compiled in based on whether the user's code is compiled with -released or not. But it is true that in any non-templated Phobos code, assertions are only good for checking Phobos during its unit tests if Phobos is compiled in release mode. IIRC though, there's a -defaultlib switch (or something close to that) which allows you to tell the compiler to use a different version of Phobos, so you can tell it to use a non-release build of Phobos, but I don't remember if we provide such a build with the released compiler or not. Regardless, most code probably won't use it, so while it's a nice idea and useful for those who put in the effort to use it, it's definitely true that most code won't benefit from it, seriously reducing the value of any assertions in non-templated Phobos code which are intended to check user code rather than Phobos itself.

- Jonathan M Davis