View mode: basic / threaded / horizontal-split · Log in · Help
March 09, 2012
Re: Assert and the optional Message
On Friday, March 09, 2012 09:59:42 H. S. Teoh wrote:
> On Fri, Mar 09, 2012 at 08:56:10AM -0800, Jonathan M Davis wrote:
> > On Friday, March 09, 2012 16:07:10 Timon Gehr wrote:
> > > On 03/09/2012 03:24 PM, Jacob Carlborg wrote:
> [...]
> 
> > > > I still want it to call finally blocks, scope statements, and
> > > > destructors.
> > > 
> > > I have never actually observed that those are not run for assertion
> > > failures.
> > 
> > The current implementation may not skip them, but if so, that might
> > actually be a bug. Errors are not intended to be recoverable, so you
> > can't rely on them hitting finally blocks, scope statements, or
> > destructors. They may very well do so at present. While it's not
> > guaranteed that they will, I'm not sure that it's guaranteed that they
> > _won't_. So, it may or may not be a bug if they do.
> > 
> > It was never intended that AssertError or any other Error be
> > particularly catchable, but it's also true that D is a systems
> > programming language, so it'll let you do stuff which is unsafe, so if
> > you know what you're doing, then there are circumstances where you can
> > get away with (unit testing is one example of where catching
> > AssertErrors might make sense). But you have to know what you're
> > doing, since it's _not_ safe.
> 
> [...]
> 
> This opens up the question of, what's the *recommended* way of writing
> unittests that check for these sorts of stuff?
> 
> For example, I believe in being thorough in unit tests, so I like to use
> them to verify that the complicated in-contract I just wrote actually
> prevents the erroneous calls that I *think* it prevents. But if catching
> AssertError's may leave the program in an undefined state, then that
> pretty much invalidates any further testing past that point (the program
> may appear to work when compiled with -funittest but actually fail in
> release mode).

If you're testing that contracts throw when they're supposed to, you're going 
to have to be very careful. Depending on what code is involved, catching the 
AssertError could have no problems whatsoever. For example

assertThrown!AssertError(func(5));

void func(int i)
in
{
assert(i == 2);
}
body
{}

wouldn't be a problem at all. There are no destructors, scope statements, or 
finally blocks involved. But something like

assertThrown!AssertError(foo(5));

int foo(int i)
out(result)
{
assert(result = == 2);
}
body
{
Bar bar;

return i;
}

could have issues if Bar has a constructor than needs to run. You just need to 
understand that destructors, scope statements, and finally blocks are not 
guaranteed to be run if an Error is thrown and avoid catching Errors in cases 
where they'd be skipped (or know enough about the state that the program would 
be in if they _were_ skipped to know that it's not going to cause problems).

Personally, I think that checking contracts is overkill, but you can do it if
you're careful.

- Jonathan M Davis
March 09, 2012
Re: Assert and the optional Message
You are right, there is also an option to "Pause when program 
finishes".

I never saw it until now. Thank you for all the replies.

On Friday, 9 March 2012 at 13:39:02 UTC, Dmitry Olshansky wrote:
> On 09.03.2012 11:42, Chris Pons wrote:
>> I am new to D and have been playing around with Assert. I 
>> figured that
>> using a message with assert would be very helpful, but 
>> unfortunately
>> when the message is printed to the console, the console closes 
>> and my
>> program ends.
>>
>> Is there any way to get a more permanent message?
>
>
>>
>> I've tried adding system("PAUSE") and it doesn't have any 
>> effect.
>>
>> Is there any way I could have the assert function print the 
>> message to a
>> file?
>>
>> I'm using VS2010 and Visual D if that is of any importance.
>>
> There is an option to redirect all console output to "Output" 
> window. Right on the same window where you can choose a 
> debugger (mago/visual studio) IRC.
March 09, 2012
Re: Assert and the optional Message
On Friday, March 09, 2012 19:23:20 Timon Gehr wrote:
> On 03/09/2012 05:56 PM, Jonathan M Davis wrote:
> > The current implementation may not skip them, but if so, that might
> > actually be a bug. Errors are not intended to be recoverable, so you
> > can't rely on them hitting finally blocks, scope statements, or
> > destructors. They may very well do so at present. While it's not
> > guaranteed that they will, I'm not sure that it's guaranteed that they
> > _won't_. So, it may or may not be a bug if they do.
> > 
> > It was never intended that AssertError or any other Error be particularly
> > catchable, but it's also true that D is a systems programming language, so
> > it'll let you do stuff which is unsafe, so if you know what you're doing,
> > then there are circumstances where you can get away with (unit testing is
> > one example of where catching AssertErrors might make sense). But you
> > have to know what you're doing, since it's _not_ safe.
> > 
> > - Jonathan M Davis
> 
> AssertErrors must be recoverable because of the way contracts work.

In what way? Yes, they're _catchable_, but everything that was on the unwound 
portion of the stack is now in an undefined state. So, recovering from the 
AssertError and continuing execution doesn't work. So, a handler can catch the 
AssertError and do something before letting it kill the program, but portions 
of the program are definitely in an undefined state when an AssertError is 
caught. The closer the catch point is to the throw point, the less of an issue 
that is, but unless you can guarantee that no destructors, scope statements, 
or finally blocks were between the throw point and the catch point, then some 
portion of the program is in an undefined state, and continuing program 
execution is a bad idea. It _is_ possible to catch an AssertError, but you 
have to be very careful about what you do after that.

I'm not aware of anything in contracts which would involve catching an 
AssertError and then continuing execution. When a contract fails, it's going 
to kill the program just like any other assertion failure does. So, I'm not 
quite sure what you're referring to.

- Jonathan M Davis
March 09, 2012
Re: Assert and the optional Message
On Fri, Mar 09, 2012 at 01:37:38PM -0500, Jonathan M Davis wrote:
> On Friday, March 09, 2012 09:59:42 H. S. Teoh wrote:
[...]
> > This opens up the question of, what's the *recommended* way of
> > writing unittests that check for these sorts of stuff?
> > 
> > For example, I believe in being thorough in unit tests, so I like to
> > use them to verify that the complicated in-contract I just wrote
> > actually prevents the erroneous calls that I *think* it prevents.
> > But if catching AssertError's may leave the program in an undefined
> > state, then that pretty much invalidates any further testing past
> > that point (the program may appear to work when compiled with
> > -funittest but actually fail in release mode).
> 
> If you're testing that contracts throw when they're supposed to,
> you're going to have to be very careful. Depending on what code is
> involved, catching the AssertError could have no problems whatsoever.
> For example
> 
> assertThrown!AssertError(func(5));
> 
> void func(int i)
> in
> {
>  assert(i == 2);
> }
> body
> {}
> 
> wouldn't be a problem at all. There are no destructors, scope
> statements, or finally blocks involved. But something like
> 
> assertThrown!AssertError(foo(5));
> 
> int foo(int i)
> out(result)
> {
>  assert(result = == 2);
> }
> body
> {
>  Bar bar;
> 
>  return i;
> }
> 
> could have issues if Bar has a constructor than needs to run. You just
> need to understand that destructors, scope statements, and finally
> blocks are not guaranteed to be run if an Error is thrown and avoid
> catching Errors in cases where they'd be skipped (or know enough about
> the state that the program would be in if they _were_ skipped to know
> that it's not going to cause problems).
> 
> Personally, I think that checking contracts is overkill, but you can
> do it if you're careful.
[...]

Hmph. Well, then that defeats the purpose of checking contracts, because
checking contracts is only justifiable if it's complex enough, which
means that it's liable to involve things like dtors and scope
statements.  It's silly to want to check a trivial contract like
assert(x>0);, because if something *that* simple can go wrong, then so
can the unittest, so you're not proving anything at all.

But this isn't that big a deal. One could argue that if a contract is
convoluted enough to warrant a unit test, then perhaps most (or all) of
its complexity should be factored out into a separate, unit tested
function, which is then just invoked from the contract.

(I find this a bit ironic, since TDPL states that the reason contracts
allow statements is so that complicated conditions can be tested for,
rather than being limited to just a single expression, as is the case in
most other languages that support DbC. Now it seems that simple
contracts are the way to go.)


T

-- 
MASM = Mana Ada Sistem, Man!
March 09, 2012
Re: Assert and the optional Message
On Friday, March 09, 2012 11:29:43 H. S. Teoh wrote:
> Hmph. Well, then that defeats the purpose of checking contracts, because
> checking contracts is only justifiable if it's complex enough, which
> means that it's liable to involve things like dtors and scope
> statements. It's silly to want to check a trivial contract like
> assert(x>0);, because if something *that* simple can go wrong, then so
> can the unittest, so you're not proving anything at all.
> 
> But this isn't that big a deal. One could argue that if a contract is
> convoluted enough to warrant a unit test, then perhaps most (or all) of
> its complexity should be factored out into a separate, unit tested
> function, which is then just invoked from the contract.
> 
> (I find this a bit ironic, since TDPL states that the reason contracts
> allow statements is so that complicated conditions can be tested for,
> rather than being limited to just a single expression, as is the case in
> most other languages that support DbC. Now it seems that simple
> contracts are the way to go.)

It's only an issue if you're trying to test your contracts, and I don't think 
that that's a very typical thing to do. That's kind of like writing tests to 
test your unit tests.

And the ability to have complicated conditions in contracts is still better 
than having a single expression even if you do want to test your more 
complicated contracts, because it allows you to have multiple assertions 
rather than just one expression, and then you know _which_ condition was false 
and can provide a decent error message (e.g. one which included the values of 
some of the arguments) instead of having one big condition that either 
succeeds or fails and really doesn't give you any useful information beyond 
that (like you get with template constraints).

- Jonathan M Davis
March 09, 2012
Re: Assert and the optional Message
On Fri, Mar 09, 2012 at 02:38:48PM -0500, Jonathan M Davis wrote:
> On Friday, March 09, 2012 11:29:43 H. S. Teoh wrote:
> > Hmph. Well, then that defeats the purpose of checking contracts,
> > because checking contracts is only justifiable if it's complex
> > enough, which means that it's liable to involve things like dtors
> > and scope statements. It's silly to want to check a trivial contract
> > like assert(x>0);, because if something *that* simple can go wrong,
> > then so can the unittest, so you're not proving anything at all.
> > 
> > But this isn't that big a deal. One could argue that if a contract
> > is convoluted enough to warrant a unit test, then perhaps most (or
> > all) of its complexity should be factored out into a separate, unit
> > tested function, which is then just invoked from the contract.
> > 
> > (I find this a bit ironic, since TDPL states that the reason
> > contracts allow statements is so that complicated conditions can be
> > tested for, rather than being limited to just a single expression,
> > as is the case in most other languages that support DbC. Now it
> > seems that simple contracts are the way to go.)
> 
> It's only an issue if you're trying to test your contracts, and I
> don't think that that's a very typical thing to do. That's kind of
> like writing tests to test your unit tests.

I was thinking of cases like a function that performs complicated
numerical computations, and the out contract is to assert that the
results make sense (e.g., you're not getting total garbage due to
accumulated roundoff errors). Sometimes checking if the results are
consistent is non-trivial.

But then again, if it's *that* non-trivial, it really shouldn't be
directly inside a contract, but in a separate function.


> And the ability to have complicated conditions in contracts is still
> better than having a single expression even if you do want to test
> your more complicated contracts, because it allows you to have
> multiple assertions rather than just one expression, and then you know
> _which_ condition was false and can provide a decent error message
> (e.g. one which included the values of some of the arguments) instead
> of having one big condition that either succeeds or fails and really
> doesn't give you any useful information beyond that (like you get with
> template constraints).
[...]

I wasn't arguing for using only a single expression in contracts at all.
I was just commenting that allowing statements makes it possible to do a
whole lot more, including stuff that perhaps one shouldn't be doing
inside a contract. But I've always believed in flexibility vs.
unnecessary restrictions. Preventing the programmer from doing stupid
things will also prevent her from doing clever things, as the saying
goes.


T

-- 
MAS = Mana Ada Sistem?
March 09, 2012
Re: Assert and the optional Message
On 03/09/2012 07:37 PM, H. S. Teoh wrote:
> On Fri, Mar 09, 2012 at 07:23:20PM +0100, Timon Gehr wrote:
>> On 03/09/2012 05:56 PM, Jonathan M Davis wrote:
> [...]
>>> It was never intended that AssertError or any other Error be
>>> particularly catchable, but it's also true that D is a systems
>>> programming language, so it'll let you do stuff which is unsafe, so
>>> if you know what you're doing, then there are circumstances where you
>>> can get away with (unit testing is one example of where catching
>>> AssertErrors might make sense). But you have to know what you're
>>> doing, since it's _not_ safe.
>>>
>>> - Jonathan M Davis
>>
>> AssertErrors must be recoverable because of the way contracts work.
>
> Are you referring to contract AssertErrors in unittests, or in general?
>
> In general, I think contracts *should* terminate the program with
> extreme prejudice when they fail. It represents assumptions about
> internal consistency being broken, which makes it unsafe to do
> otherwise.
>
> But in unittests where these assumptions are deliberately broken (to
> ensure the contract does what you think it does), it makes sense to be
> able to "recover" from AssertErrors.
>
>
> T
>

'in' contracts must catch assertion failures because it is enough if one 
of them passes.


class Foo{
    void foo(int x)in{assert(x==0);}body{}
}
class Bar: Foo{
    void foo(int x)in{assert(x==1);}body{}
}

void main(){
    Bar bar = new Bar;
    bar.foo(0); // ok
    bar.foo(1); // ok
}
March 09, 2012
Re: Assert and the optional Message
On 03/09/2012 08:29 PM, H. S. Teoh wrote:
> On Fri, Mar 09, 2012 at 01:37:38PM -0500, Jonathan M Davis wrote:
>> On Friday, March 09, 2012 09:59:42 H. S. Teoh wrote:
> [...]
>>> This opens up the question of, what's the *recommended* way of
>>> writing unittests that check for these sorts of stuff?
>>>
>>> For example, I believe in being thorough in unit tests, so I like to
>>> use them to verify that the complicated in-contract I just wrote
>>> actually prevents the erroneous calls that I *think* it prevents.
>>> But if catching AssertError's may leave the program in an undefined
>>> state, then that pretty much invalidates any further testing past
>>> that point (the program may appear to work when compiled with
>>> -funittest but actually fail in release mode).
>>
>> If you're testing that contracts throw when they're supposed to,
>> you're going to have to be very careful. Depending on what code is
>> involved, catching the AssertError could have no problems whatsoever.
>> For example
>>
>> assertThrown!AssertError(func(5));
>>
>> void func(int i)
>> in
>> {
>>   assert(i == 2);
>> }
>> body
>> {}
>>
>> wouldn't be a problem at all. There are no destructors, scope
>> statements, or finally blocks involved. But something like
>>
>> assertThrown!AssertError(foo(5));
>>
>> int foo(int i)
>> out(result)
>> {
>>   assert(result = == 2);
>> }
>> body
>> {
>>   Bar bar;
>>
>>   return i;
>> }
>>
>> could have issues if Bar has a constructor than needs to run. You just
>> need to understand that destructors, scope statements, and finally
>> blocks are not guaranteed to be run if an Error is thrown and avoid
>> catching Errors in cases where they'd be skipped (or know enough about
>> the state that the program would be in if they _were_ skipped to know
>> that it's not going to cause problems).
>>
>> Personally, I think that checking contracts is overkill, but you can
>> do it if you're careful.
> [...]
>
> Hmph. Well, then that defeats the purpose of checking contracts, because
> checking contracts is only justifiable if it's complex enough, which
> means that it's liable to involve things like dtors and scope
> statements.  It's silly to want to check a trivial contract like
> assert(x>0);, because if something *that* simple can go wrong, then so
> can the unittest, so you're not proving anything at all.
>
> But this isn't that big a deal. One could argue that if a contract is
> convoluted enough to warrant a unit test, then perhaps most (or all) of
> its complexity should be factored out into a separate, unit tested
> function, which is then just invoked from the contract.
>
> (I find this a bit ironic, since TDPL states that the reason contracts
> allow statements is so that complicated conditions can be tested for,
> rather than being limited to just a single expression, as is the case in
> most other languages that support DbC. Now it seems that simple
> contracts are the way to go.)
>
>
> T
>

Jonathan is just speculating. And I think he is wrong.
March 09, 2012
Re: Assert and the optional Message
On Friday, March 09, 2012 22:03:11 Timon Gehr wrote:
> On 03/09/2012 08:29 PM, H. S. Teoh wrote:
> > On Fri, Mar 09, 2012 at 01:37:38PM -0500, Jonathan M Davis wrote:
> >> On Friday, March 09, 2012 09:59:42 H. S. Teoh wrote:
> > [...]
> > 
> >>> This opens up the question of, what's the *recommended* way of
> >>> writing unittests that check for these sorts of stuff?
> >>> 
> >>> For example, I believe in being thorough in unit tests, so I like to
> >>> use them to verify that the complicated in-contract I just wrote
> >>> actually prevents the erroneous calls that I *think* it prevents.
> >>> But if catching AssertError's may leave the program in an undefined
> >>> state, then that pretty much invalidates any further testing past
> >>> that point (the program may appear to work when compiled with
> >>> -funittest but actually fail in release mode).
> >> 
> >> If you're testing that contracts throw when they're supposed to,
> >> you're going to have to be very careful. Depending on what code is
> >> involved, catching the AssertError could have no problems whatsoever.
> >> For example
> >> 
> >> assertThrown!AssertError(func(5));
> >> 
> >> void func(int i)
> >> in
> >> {
> >> 
> >> assert(i == 2);
> >> 
> >> }
> >> body
> >> {}
> >> 
> >> wouldn't be a problem at all. There are no destructors, scope
> >> statements, or finally blocks involved. But something like
> >> 
> >> assertThrown!AssertError(foo(5));
> >> 
> >> int foo(int i)
> >> out(result)
> >> {
> >> 
> >> assert(result = == 2);
> >> 
> >> }
> >> body
> >> {
> >> 
> >> Bar bar;
> >> 
> >> return i;
> >> 
> >> }
> >> 
> >> could have issues if Bar has a constructor than needs to run. You just
> >> need to understand that destructors, scope statements, and finally
> >> blocks are not guaranteed to be run if an Error is thrown and avoid
> >> catching Errors in cases where they'd be skipped (or know enough about
> >> the state that the program would be in if they _were_ skipped to know
> >> that it's not going to cause problems).
> >> 
> >> Personally, I think that checking contracts is overkill, but you can
> >> do it if you're careful.
> > 
> > [...]
> > 
> > Hmph. Well, then that defeats the purpose of checking contracts, because
> > checking contracts is only justifiable if it's complex enough, which
> > means that it's liable to involve things like dtors and scope
> > statements. It's silly to want to check a trivial contract like
> > assert(x>0);, because if something *that* simple can go wrong, then so
> > can the unittest, so you're not proving anything at all.
> > 
> > But this isn't that big a deal. One could argue that if a contract is
> > convoluted enough to warrant a unit test, then perhaps most (or all) of
> > its complexity should be factored out into a separate, unit tested
> > function, which is then just invoked from the contract.
> > 
> > (I find this a bit ironic, since TDPL states that the reason contracts
> > allow statements is so that complicated conditions can be tested for,
> > rather than being limited to just a single expression, as is the case in
> > most other languages that support DbC. Now it seems that simple
> > contracts are the way to go.)
> > 
> > 
> > T
> 
> Jonathan is just speculating. And I think he is wrong.

Speculating about what?

- Jonathan M Davis
March 09, 2012
Re: Assert and the optional Message
On 03/09/2012 10:43 PM, Jonathan M Davis wrote:
...
>>
>> Jonathan is just speculating. And I think he is wrong.
>
> Speculating about what?
>
> - Jonathan M Davis

About how assertion failures affect struct destructors, finally 
statements and scope statements. If they wouldn't be executed upon 
thrown AssertError, then a _passing_ in contract could screw up the 
program state. Furthermore, the implementation does execute them.
1 2 3 4 5
Top | Discussion index | About this forum | D home