January 20, 2012
On Thu, 19 Jan 2012 23:24:59 -0500, Jonathan M Davis <jmdavisProg@gmx.com> wrote:

> On Thursday, January 19, 2012 23:19:02 Steven Schveighoffer wrote:
>> Imagine you have 1000 lines of code that call 50 or so
>> different methods on a class.  Any one of those calls in any one of those
>> methods could cause an invariant failure.  But only one method call can
>> cause a specific out condition failure, and the lines of code that call
>> that function might be significantly less than 1000 (maybe a handful).
>
> Won't you be able to see exactly which function failed in the stack trace? Or
> does it not show up, because the invariant is checked _after_ the function
> call? I would still think that the stack trace would make it fairly clear even
> if that's the case.

If you get one (that is human decipherable).  This doesn't always happen.  But like Walter and you said, the order is irrelevant to the execution of the program, why make the developer work harder than he has to?  It makes no sense to me *not* to change it.

-Steve
January 20, 2012
On 1/19/2012 8:19 PM, Steven Schveighoffer wrote:
> If they are related, yes it does give you more information. The out condition
> might not check the class data directly, but the error which caused the
> invariant to fail could have also caused the out-condition to fail. It's
> inconsequential to the *program* whether the out condition or the invariant
> halts execution. But to the developer receiving the assert message, it's much
> more helpful to see an out condition failing than an invariant. If they are
> related, and caused by the same bug, it's that much more helpful.

I utterly fail to understand your argument about it being more helpful.


> Imagine you
> have 1000 lines of code that call 50 or so different methods on a class. Any one
> of those calls in any one of those methods could cause an invariant failure. But
> only one method call can cause a specific out condition failure, and the lines
> of code that call that function might be significantly less than 1000 (maybe a
> handful).

This does not make sense to me. If a bug would cause an invariant failure and an out failure, and one is run right after the other, there is zero advantage to one being run before the other.

   assert(s);
   assert(s);

which one should be run first?

> With almost no change to execution speed, semantics, or pretty much anything,
> you will have saved the developer minutes to hours (under the right
> circumstances, maybe even days or weeks) of crappy "how the hell do I find this
> bug" time.

I see no advantage, even to your hypothetical. I think you would be *very* hard pressed to come up with an example.

> I can't see a single drawback aside from the time it takes to test
> the changes to the compiler.

Changing the language requires more than no drawbacks, it requires a compelling demonstration of value added.

> even your second reason is flawed -- in order for there to be a noticeable
> difference, one would have to make their invariant actually *change* the object.
> Why do we support that? In fact, this change would help them discover their
> flawed invariant code :)

Invariants and conditions are allowed to be impure so they can do things like logging.
January 20, 2012
On Thursday, January 19, 2012 21:01:40 Walter Bright wrote:
> Invariants and conditions are allowed to be impure so they can do things like logging.

Yeah, but if they're modifying state, they're doing something which is essentially invalid, so from the standpoint of breaking code, I don't think that swapping the order invariants and post-conditions is really an issue. I think that it's just a question of which order makes more sense. If that's what it is now, then great, we'll leave it as-is. If it's the other way around, then I very much doubt that it would negatively impact much code (if any) to swap them, since the order really isn't supposed to matter.

- Jonathan M Davis
January 20, 2012
On 1/19/2012 9:14 PM, Jonathan M Davis wrote:
> Yeah, but if they're modifying state, they're doing something which is
> essentially invalid,

Yup, so arguing for which order the state changes should come in is also invalid.

> so from the standpoint of breaking code, I don't think
> that swapping the order invariants and post-conditions is really an issue. I
> think that it's just a question of which order makes more sense. If that's
> what it is now, then great, we'll leave it as-is. If it's the other way
> around, then I very much doubt that it would negatively impact much code (if
> any) to swap them, since the order really isn't supposed to matter.

I'm not going to swap them without a compelling demonstration of its advantages. Not breaking much code is not an argument for changing current behavior.

January 20, 2012
2012/1/20 bearophile <bearophileHUGS@lycos.com>:
> Walter has recently closed a bug report without fixing it and without an answer, it's about contract based programming: http://d.puremagic.com/issues/show_bug.cgi?id=5024
>
> So I'm asking for more info here.
>
> As reference I use this little program (I have improved it a bit compared to the one inside issue 5024):
>
>
>
> import std.c.stdio: printf;
>
> class Foo {
>    int x = 0;
>
>    invariant() {
>        printf("Foo invariant: x=%d\n", x);
>        assert(x >= 0);
>    }
>
>    this() {
>        printf("Foo constructor: x=%d\n", x);
>        x = 1;
>    }
>
>    void setX(int newx)
>        in {
>            printf("Foo.setX precondition: newx=%d\n", newx);
>            assert(newx >= 0);
>        } out {
>            printf("Foo.setX postcondition: x=%d\n", x);
>            assert(x == newx);
>        } body {
>            printf("Foo.setX body\n");
>            x = newx;
>        }
> }
>
> void main() {
>    auto c = new Foo();
>    c.setX(10);
> }
>
>
>
> Currently it prints this, that I don't like:
>
>
> Foo constructor: x=0
> Foo invariant: x=1
> Foo.setX precondition: newx=10
> Foo invariant: x=1
> Foo.setX body
> Foo invariant: x=10
> Foo.setX postcondition: x=10
>
>
>
> I'd like this order:
>
> Foo constructor: x=0
> Foo invariant: x=1
> Foo invariant: x=1
> Foo.setX precondition: newx=10
> Foo.setX body
> Foo.setX postcondition: x=10
> Foo invariant: x=10
>
>
> An example of why I think that's better. This is the same program with a bug:
>
>
> import std.c.stdio: printf;
>
> class Foo {
>    int x = 0;
>
>    invariant() {
>        printf("Foo invariant: x=%d\n", x);
>        assert(x >= 0); // line 8
>    }
>
>    this() {
>        printf("Foo constructor: x=%d\n", x);
>        x = 1;
>    }
>
>    void setX(int newx)
>        in {
>            printf("Foo.setX precondition: newx=%d\n", newx);
>            assert(newx >= 0);
>        } out {
>            printf("Foo.setX postcondition: x=%d\n", x);
>            assert(x == newx); // line 22
>        } body {
>            printf("Foo.setX body\n");
>            x = -newx;
>        }
> }
>
> void main() {
>    auto c = new Foo();
>    c.setX(10);
> }
>
>
> If I run it it gives:
> core.exception.AssertError@test2(8): Assertion failure
>
>
> So the bug is caught by a the generic invariant at line 8 instead of what I think is the correct place, the setX post-condition at line 22. The post-condition is a test meant to verify that the setX() body is correct, while the invariant contains more general tests. So I think it's more right to run the specific tests first, and the more general later.
>
> If I am mistaken please I'd like to know why the current design is better (or maybe why it's just equally good).
> Thank you :-)
> Bye,
> bearophile

I can think of somewhat this example:

struct Foo {
    int x = 1;

    invariant() {
        assert( x >= 0 );
    }

    int do_calc( int y )
    in {
        assert( y >= 0 );
    } out( result ) {
        assert( result >= 0 );
    } body {
        x *= -1;     //<- bug
        return x * y;
    }
}

The bug here is caused by accidental object corruption, and invariant tells that. If assertions are swapped, we will get error at out contract, which suggests that error is in calculus algorithm.
January 20, 2012
Walter Bright wrote:

> I'm not going to swap them without a compelling demonstration of its advantages.

If there are advantages, then the specs are wrong, because they do not define the sequence of execution and an optimizing compiler might put the calls to <condition>s and `invariant' into different threads executed in parallel.

-manfred
January 20, 2012
On 1/20/2012 12:23 AM, Manfred Nowak wrote:
> If there are advantages, then the specs are wrong,

I recently fixed the specs to define the sequence.
January 20, 2012
On Fri, 20 Jan 2012 00:01:40 -0500, Walter Bright <newshound2@digitalmars.com> wrote:

> On 1/19/2012 8:19 PM, Steven Schveighoffer wrote:
>> If they are related, yes it does give you more information. The out condition
>> might not check the class data directly, but the error which caused the
>> invariant to fail could have also caused the out-condition to fail. It's
>> inconsequential to the *program* whether the out condition or the invariant
>> halts execution. But to the developer receiving the assert message, it's much
>> more helpful to see an out condition failing than an invariant. If they are
>> related, and caused by the same bug, it's that much more helpful.
>
> I utterly fail to understand your argument about it being more helpful.

For a class with 50 methods:

invariant error -> one of your 50 methods may have messed up the invariant, but I'm not going to tell you which one.  Also, it could have been messed up somewhere else, and failed at the beginning of a method call, or an extraneous assert.  Have fun looking for where the bug is.
out condition error -> method 25 failed condition at line X.

>> Imagine you
>> have 1000 lines of code that call 50 or so different methods on a class. Any one
>> of those calls in any one of those methods could cause an invariant failure. But
>> only one method call can cause a specific out condition failure, and the lines
>> of code that call that function might be significantly less than 1000 (maybe a
>> handful).
>
> This does not make sense to me. If a bug would cause an invariant failure and an out failure, and one is run right after the other, there is zero advantage to one being run before the other.
>
>     assert(s);
>     assert(s);
>
> which one should be run first?

They are not *located* one right after another.  One is in the invariant function which could be called from anywhere, and one is directly attached to the code which caused the bug.  Asserts are not only helpful by telling you that they failed, but also *where* they failed.  It's not always guaranteed that you get a useful stack trace to see where the program is running, but you do always get an assert message.

>
>> With almost no change to execution speed, semantics, or pretty much anything,
>> you will have saved the developer minutes to hours (under the right
>> circumstances, maybe even days or weeks) of crappy "how the hell do I find this
>> bug" time.
>
> I see no advantage, even to your hypothetical. I think you would be *very* hard pressed to come up with an example.

I've had programs that I have written which failed once every 2 weeks.

If such a situation happens, and you just get a single-line assert message, then you have to instrument, or run in debugger, wait another 2 weeks.  Or maybe you get a stack trace without any readable.  Not as bad as waiting two weeks, but if you can tell me more information about where the program is without me having to get out my stack decoder ring, DO IT!

My philosophy to error reporting is, give me as much information as possible about the current state of the program.  Especially for errors which are about to make all the evidence go away (aborting errors).  It's not perfection, it's not even guaranteed, but do whatever is possible to make things easier to figure out without complex tools.

This is a small change for a small gain, but it's a very very simple change.  You just reorder one generated call.  The cost is probably less than the effort we have expended discussing this.

>> even your second reason is flawed -- in order for there to be a noticeable
>> difference, one would have to make their invariant actually *change* the object.
>> Why do we support that? In fact, this change would help them discover their
>> flawed invariant code :)
>
> Invariants and conditions are allowed to be impure so they can do things like logging.

How does this destroy prior work?  Log messages are slightly out of order?  Still not buying it.

-Steve
January 20, 2012
Walter Bright wrote:

> I recently fixed the specs to define the sequence.

Then the Status Quo holds. One more remark:

if the intention still is, that contracts are to be seen as an executable description of at least parts of the design, then the current specification of the language does not give any control over those contracts to the designers.

This is because the coder can easily change the contracts and then the designer would have a hard time to find that modifications.

This could be changed for eaxmple by compiling the contracts into a separate library but seems not to be supported.

Are there other ways to garantie, that the code the coder delivers to the designer indeed fulfills the requirements the designer gave before handing out the job?




January 20, 2012
On 1/20/2012 10:42 AM, Manfred Nowak wrote:
> if the intention still is, that contracts are to be seen as an
> executable description of at least parts of the design, then the
> current specification of the language does not give any control over
> those contracts to the designers.
>
> This is because the coder can easily change the contracts and then the
> designer would have a hard time to find that modifications.

D isn't a language that is designed to prevent deliberate subversion - only inadvertent subversion.


> This could be changed for eaxmple by compiling the contracts into a
> separate library but seems not to be supported.
>
> Are there other ways to garantie, that the code the coder delivers to
> the designer indeed fulfills the requirements the designer gave before
> handing out the job?

You can have your contracts call functions in an external library.