www.digitalmars.com         C & C++   DMDScript  

digitalmars.D.learn - assert and enforce both compiled out with -release

reply kdevel <kdevel vogtner.de> writes:
https://dlang.org/phobos/std_exception.html#enforce states:

| Also, do not use enforce inside of contracts (i.e. inside of in 
and out blocks
| and invariants), because they will be compiled out when 
compiling with -release.
| Use assert in contracts.

But assert is also ignored in release mode:

ass.d
---
void foo (int i)
in {
    assert (i < 0);
}
body {
}

void main ()
{
    foo (1);
}
---

$ dmd ass
$ ./ass
core.exception.AssertError ass.d(3): Assertion failure
----------------
??:? _d_assertp [0x42a065]
??:? void ass.foo(int) [0x429f9d]
??:? _Dmain [0x429fad]

$ dmd -release ass
$ ./ass
[nothing]
Jan 27 2018
next sibling parent rjframe <dlang ryanjframe.com> writes:
On Sat, 27 Jan 2018 13:52:47 +0000, kdevel wrote:

 https://dlang.org/phobos/std_exception.html#enforce states:
 
 | Also, do not use enforce inside of contracts (i.e. inside of in and
 out blocks | and invariants), because they will be compiled out when
 compiling with -release.
 | Use assert in contracts.
 
 But assert is also ignored in release mode:
 
enforce is a wrapper around try/catch (I don't know if that's technically true, but it is pragmatically true); assert is a debug tool. Contracts and assertions are removed for release builds, which means if you place an enforce in a contract, it's removed - but the same enforce placed in the function body would remain. You don't want the enforce stripped from the exe (if you are OK with that, it should be an assertion), so it shouldn't be in the contract. Use assertions to catch programming bugs, and enforce or try/catch for exceptions. If DIP 1006[0] is accepted, we'll have greater control over the removal of asserts and contracts in release mode. [0]: https://github.com/dlang/DIPs/blob/master/DIPs/DIP1006.md
Jan 27 2018
prev sibling parent reply =?UTF-8?Q?Ali_=c3=87ehreli?= <acehreli yahoo.com> writes:
On 01/27/2018 05:52 AM, kdevel wrote:
 https://dlang.org/phobos/std_exception.html#enforce states:

 | Also, do not use enforce inside of contracts (i.e. inside of in and
 out blocks
 | and invariants), because they will be compiled out when compiling with
 -release.
 | Use assert in contracts.

 But assert is also ignored in release mode:
The documentation is not clear. "they will be compiled out" means "contracts are compiled out". So, an enforce() would disappear if it's inside such a block, which should not be what the programmer wants for an enforce(). Fixed it through the "Improve this page" link on that Phobos page: https://github.com/dlang/phobos/blob/master/std/exception.d Ali
Jan 27 2018
next sibling parent reply kdevel <kdevel vogtner.de> writes:
On Saturday, 27 January 2018 at 14:31:13 UTC, Ali Çehreli wrote:
 But assert is also ignored in release mode:
The documentation is not clear. "they will be compiled out" means "contracts are compiled out". So, an enforce() would disappear if it's inside such a block, which should not be what the programmer wants for an enforce().
The documentation was clear as glass (but wrong): "Use assert in contracts."
 Fixed it through the "Improve this page" link on that Phobos 
 page:

   https://github.com/dlang/phobos/blob/master/std/exception.d
"Use $(D assert) in contracts." is still in there.
Jan 27 2018
parent reply =?UTF-8?Q?Ali_=c3=87ehreli?= <acehreli yahoo.com> writes:
On 01/27/2018 06:36 AM, kdevel wrote:
 On Saturday, 27 January 2018 at 14:31:13 UTC, Ali Çehreli wrote:
 But assert is also ignored in release mode:
The documentation is not clear. "they will be compiled out" means "contracts are compiled out". So, an enforce() would disappear if it's inside such a block, which should not be what the programmer wants for an enforce().
The documentation was clear as glass (but wrong): "Use assert in contracts."
 Fixed it through the "Improve this page" link on that Phobos page:

   https://github.com/dlang/phobos/blob/master/std/exception.d
"Use $(D assert) in contracts." is still in there.
What's wrong with that? What documentation is trying to say is "do not use enforce in contracts; use assert in contracts" and that's exactly the idea. Ali
Jan 27 2018
parent reply kdevel <kdevel vogtner.de> writes:
On Saturday, 27 January 2018 at 14:51:23 UTC, Ali Çehreli wrote:
 On 01/27/2018 06:36 AM, kdevel wrote:
 On Saturday, 27 January 2018 at 14:31:13 UTC, Ali Çehreli 
 wrote:
 But assert is also ignored in release mode:
The documentation is not clear. "they will be compiled out" means "contracts are compiled out". So, an enforce() would disappear if it's inside such a block, which should not be what the programmer wants for an enforce().
The documentation was clear as glass (but wrong): "Use assert in contracts."
 Fixed it through the "Improve this page" link on that Phobos 
 page:

   https://github.com/dlang/phobos/blob/master/std/exception.d
"Use $(D assert) in contracts." is still in there.
What's wrong with that? What documentation is trying to say is "do not use enforce in contracts; use assert in contracts" and that's exactly the idea.
I can't see a problem which would be solved by following this advice. It distracts the reader (me) from gettin his (my) work done. If I compile not for release both, enforce and assert, are in effect. If I compile for release both, enforce and assert, are disabled. So by replacing enforce with assert I gain nothing.
Jan 27 2018
parent reply Jonathan M Davis <newsgroup.d jmdavisprog.com> writes:
On Saturday, January 27, 2018 14:59:50 kdevel via Digitalmars-d-learn wrote:
 On Saturday, 27 January 2018 at 14:51:23 UTC, Ali Çehreli wrote:
 On 01/27/2018 06:36 AM, kdevel wrote:
 On Saturday, 27 January 2018 at 14:31:13 UTC, Ali Çehreli

 wrote:
 But assert is also ignored in release mode:
The documentation is not clear. "they will be compiled out" means "contracts are compiled out". So, an enforce() would disappear if it's inside such a block, which should not be what the programmer wants for an enforce().
The documentation was clear as glass (but wrong): "Use assert in contracts."
 Fixed it through the "Improve this page" link on that Phobos
 page:

   https://github.com/dlang/phobos/blob/master/std/exception.d
"Use $(D assert) in contracts." is still in there.
What's wrong with that? What documentation is trying to say is "do not use enforce in contracts; use assert in contracts" and that's exactly the idea.
I can't see a problem which would be solved by following this advice. It distracts the reader (me) from gettin his (my) work done. If I compile not for release both, enforce and assert, are in effect. If I compile for release both, enforce and assert, are disabled. So by replacing enforce with assert I gain nothing.
No, enforce is _not_ disabled with -release. e.g. void foo(int i) { enforce(i > 42); } void main() { foo(0); } will throw an exception even when you compile with -release. The problem is that you're using enforce inside a contract instead of inside the function's body. Contracts are specifically for asserting pre and post conditions. It is expected that they only be used for assertions or for code which is going to be run in preparation for running an assertion. They are _not_ for code which is intended to be part of the final program, and they are compiled out with -release, just like assertions are compiled out elsewhere in the code. As such, any code in a contract - be it an assertion, a call to enforce, or any arbitarily complex piece of code - will not be in the final program. Anything that you want in your final program should not be in a contract. If you want to use exceptions - be it with enforce or with an if statement and explicitly throwing - then don't put them in any contracts. They _will_ get compiled out. As such, it makes no sense to use enforce in a contract. It should go in the function body. - Jonathan M Davis
Jan 27 2018
parent reply kdevel <kdevel vogtner.de> writes:
On Saturday, 27 January 2018 at 16:19:30 UTC, Jonathan M Davis 
wrote:
 On Saturday, January 27, 2018 14:59:50 kdevel via 
 Digitalmars-d-learn wrote:
 https://github.com/dlang/phobos/blob/master/std/exception.d
"Use $(D assert) in contracts." is still in there.
What's wrong with that? What documentation is trying to say is "do not use enforce in contracts; use assert in contracts" and that's exactly the idea.
I can't see a problem which would be solved by following this advice. It distracts the reader (me) from gettin his (my) work done. If I compile not for release both, enforce and assert, are in effect. If I compile for release both, enforce and assert, are disabled. So by replacing enforce with assert I gain nothing.
No, enforce is _not_ disabled with -release. e.g.
That's not my point.
 void foo(int i)
 {
     enforce(i > 42);
 }

 void main()
 {
     foo(0);
 }
This is a different case.
 will throw an exception even when you compile with -release. 
 The problem is that you're using enforce inside a contract 
 instead of inside the function's body.
This is not a problem, because this is perfectly legal. The problem is the wording of this phrase on the docs: | Also, do not use enforce inside of contracts (i.e. inside of in and out blocks | and invariants), because they will be compiled out when compiling with | -release. Use assert in contracts. Using assert *IN* contracts in -release mode is equally pointless.
 Contracts are specifically for asserting pre and post 
 conditions. It is expected that they only be used for 
 assertions or for code which is going to be run in preparation 
 for running an assertion. They are _not_ for code which is 
 intended to be part of the final program, and they are compiled 
 out with -release, just like assertions are compiled out 
 elsewhere in the code. As such, any code in a contract - be it 
 an assertion, a call to enforce, or any arbitarily complex 
 piece of code - will not be in the final program.
Then please explain the meaning of the sentence Use assert in contracts. in this context: | Also, do not use enforce inside of contracts (i.e. inside of in and out blocks | and invariants), because they will be compiled out when compiling with | -release. Use assert in contracts. to me. IMHO this advice is pointless.
 Anything that you want in your final program should not be in a 
 contract. If you want to use exceptions - be it with enforce or 
 with an if statement and explicitly throwing - then don't put 
 them in any contracts. They _will_ get compiled out. As such, 
 it makes no sense to use enforce in a contract. It should go in 
 the function body.
Then please explain to me, in which respect the advice to "Use assert[s] in contracs" makes sense if the contracts are to be compiled out. I don't get it.
Jan 27 2018
next sibling parent reply rjframe <dlang ryanjframe.com> writes:
On Sat, 27 Jan 2018 17:12:25 +0000, kdevel wrote:

 
 This is not a problem, because this is perfectly legal. The problem is
 the wording of this phrase on the docs:
 
 | Also, do not use enforce inside of contracts (i.e. inside of in and
 out blocks | and invariants), because they will be compiled out when
 compiling with | -release. Use assert in contracts.
 
 Using assert *IN* contracts in -release mode is equally pointless.
...
 | Also, do not use enforce inside of contracts (i.e. inside of in and
 out blocks | and invariants), because they will be compiled out when
 compiling with | -release. Use assert in contracts.
 
 to me. IMHO this advice is pointless.
...
 Then please explain to me, in which respect the advice to "Use assert[s]
 in contracs" makes sense if the contracts are to be compiled out. I
 don't get it.
I think I see what you mean; you interpret "use asserts, because enforce will be compiled out" to imply that asserts wouldn't be compiled out, correct? Since, in reality, both would be compiled out, it shouldn't matter what you use, so the docs shouldn't care. That makes sense. The documentation seems to assume the reader has certain expectations of assert and enforce[0], so each function expresses a different intention to the programmer; when I see `assert()` I expect those checks only in non- release mode; when I see `enforce()` I expect those checks regardless of the flags that have been set[1]. Placing `enforce` in a contract messes with that expectation. What language here would make more sense to you? Anything I can come up with is either awkward or pretty verbose. --Ryan [0]: The correct expectation, but that's not necessarily important when it's not explicitly described. [1]: So you can use enforce to validate user input, but never assert.
Jan 27 2018
parent reply kdevel <kdevel vogtner.de> writes:
On Saturday, 27 January 2018 at 18:00:32 UTC, rjframe wrote:
 I think I see what you mean; you interpret "use asserts, 
 because enforce will be compiled out" to imply that asserts 
 wouldn't be compiled out, correct?
Is there any other meaningful interpretation?
 Since, in reality, both would be compiled out, it shouldn't 
 matter what you use, so the docs shouldn't care. That makes 
 sense.
That's precisely my point.
 The documentation seems to assume the reader has certain 
 expectations of assert and enforce[0], so each function 
 expresses a different intention to the programmer; when I see 
 `assert()` I expect those checks only in non- release mode; 
 when I see `enforce()` I expect those checks regardless of the 
 flags that have been set[1]. Placing `enforce` in a contract 
 messes with that expectation.
Right.
 What language here would make more sense to you? Anything I can 
 come up with is either awkward or pretty verbose.
I suggest the deletion of the sentence "Use assert in contracts."
Jan 27 2018
parent reply =?UTF-8?Q?Ali_=c3=87ehreli?= <acehreli yahoo.com> writes:
On 01/27/2018 10:33 AM, kdevel wrote:

 I suggest the deletion of the sentence "Use assert in contracts."
Done. Ali
Jan 27 2018
parent reply lobo <swamplobo gmail.com> writes:
On Saturday, 27 January 2018 at 22:53:37 UTC, Ali Çehreli wrote:
 On 01/27/2018 10:33 AM, kdevel wrote:

 I suggest the deletion of the sentence "Use assert in 
 contracts."
Done. Ali
Wait, no this isn't right, is it? Enforce should not be used in contracts so the "Use assert in contracts" statement is correct and should remain. I think the issue here is the OP is getting confused between assert vs. exception. Contracts (in D) are used to define and assert the agreed logic behaviour of the program code. Asserts catch logic bugs in the code that may lead to incorrect behaviour at runtime. Exceptions are for exceptional cases that crop up at runtime due to factors external to the code logic, e.g. invalid external state such as failing to open a file or a sensor not going off when it should because it is faulty. Asserts can be removed in -release code because it is assumed the logic has been asserted correct during debug builds and testing. The same reason compilers now are starting to optimise out code based on assert conditions. bye, lobo
Jan 27 2018
next sibling parent =?UTF-8?Q?Ali_=c3=87ehreli?= <acehreli yahoo.com> writes:
On 01/27/2018 04:59 PM, lobo wrote:
 On Saturday, 27 January 2018 at 22:53:37 UTC, Ali Çehreli wrote:
 On 01/27/2018 10:33 AM, kdevel wrote:

 I suggest the deletion of the sentence "Use assert in contracts."
Done. Ali
Wait, no this isn't right, is it?
It is right because that statement made one person to replace 'enforce's with 'asserts's.
 Enforce should not be used in
 contracts so the "Use assert in contracts" statement is correct and
 should remain.
I don't think enforce documentation is the right place to get into such matters. Warning against a potential misuse is fine but hinting at "correct use of assert vs. enforce" is not only distracting but also misguiding.
 I think the issue here is the OP is getting confused
 between assert vs. exception.

 Contracts (in D) are used to define and assert the agreed logic
 behaviour of the program code.

 Asserts catch logic bugs in the code that may lead to incorrect
 behaviour at runtime. Exceptions are for exceptional cases that crop up
 at runtime due to factors external to the code logic, e.g. invalid
 external state such as failing to open a file or a sensor not going off
 when it should because it is faulty.

 Asserts can be removed in -release code because it is assumed the logic
 has been asserted correct during debug builds and testing. The same
 reason compilers now are starting to optimise out code based on assert
 conditions.

 bye,
 lobo
All true. Ali
Jan 27 2018
prev sibling parent rjframe <dlang ryanjframe.com> writes:
On Sun, 28 Jan 2018 00:59:12 +0000, lobo wrote:

 On Saturday, 27 January 2018 at 22:53:37 UTC, Ali Çehreli wrote:
 On 01/27/2018 10:33 AM, kdevel wrote:

 I suggest the deletion of the sentence "Use assert in contracts."
Done. Ali
Wait, no this isn't right, is it? Enforce should not be used in contracts so the "Use assert in contracts" statement is correct and should remain. I think the issue here is the OP is getting confused between assert vs. exception.
Without that statement, the documentation is still pretty clear that you shouldn't use enforce in contracts, so removing it won't hurt anything, and does make things clearer by staying on-topic.
Jan 28 2018
prev sibling parent Jonathan M Davis <newsgroup.d jmdavisprog.com> writes:
On Saturday, January 27, 2018 17:12:25 kdevel via Digitalmars-d-learn wrote:
 Then please explain to me, in which respect the advice to "Use
 assert[s] in contracs" makes sense if the contracts are to be
 compiled out. I don't get it.
The entire point of contracts is to be asserting pre or post conditions. In some cases, there really isn't much difference between putting the assertion in the contract from putting it in the body. e.g. void foo(int i) in { assert(i > 42); } do { } and void foo(int i) { assert(i > 42); } are pretty much the same, but it can matter. e.g. you can have additional lines of code in a contract that can't go in a assertion: void foo(C c, D d, int i) in { auto c = c.foo(); sort(c); assert(d.bar(i) == c); } do { } To do that in the function body, you'd either have to make it a single expression (which in some cases is easy, and other cases can't be done), or turn it into a function call where the result of the call gets asserted. That particular example necessarily isn't a huge motivator for contracts, but it can be useful. It's more useful with out contracts, because then you can have have the assertion in one place rather than with each return statement. e.g. auto foo(T t) out(retval) { assert(retval.foo() > 19); } do { if(blah) return baz(); ... if(t.s == "str") return doSomething(); ... return t.xyzzy(); } However, where contracts really matter is with classes. In order for contracts to work properly with inheritance when a function is overridden, the in contract of a derived class cannot be more restrictive than that of the base class. Otherwise, you wouldn't be able to call a function on base class reference without caring what the actual class of the object was, because you'd end up with contracts failing based on what the derived class was. However, while the in contract for a derived function can't be made stricter, it _can_ be made looser, since that wouldn't make any code fail based on what the actual object type was, and there's no reason why the derived class function couldn't work with a greater range of values than the base class function. Similarly, a derived function cannot have a looser out contract than the one in the base class, because that would violate the guarantees that the base class function makes. However, the derived function _can_ have a stricter contract, because that doesn't violate the guarantees of the base class, and there's no reason not to allow the derived class to be stricter about what it outputs. As such, with derived functions, the runtime effecively ||s all in countracts and &&s all out contracts. In an inheritance chain, _one_ of the in contracts needs to pass without throwing an AssertError, whereas none of the out contracts can fail with an AssertError. So, if you put an assertion in the in contract of a virtual function, whether it actually has to pass or not depends on what the in contracts of the other functions in the inheritance chain are, whereas if you put the assertion in the function body, it always has to pass when that function is run. However, if that function isn't run (e.g. a derived class function doesn't call the base class function), then that assertion is never run, whereas if it's in the in contract, it will be run so long as another in contract hasn't already passed. And if you put an assertion in the out contract of a virtual function, it will always be run, regardless of whether a derived class function calls a base class function. The only case where it wouldn't be run is if another out contract had already failed (in which case, the AssertError killed your program). But if you put the assertion in the function body, it will only be run if that particular function is run (which may not happen if the derived class function don't call the base class function). So, the use of contracts can make a significant difference if you're dealing with classes, but their benefits are pretty superficial outside of classes. invariants are far more useful in that they run before and after every public function call. So, you can assert the state of the object in one place, and it gets tested whenever the public API is used. Personally, I almost never use contracts. I rarely use classes, so the benefits that contracts provide in that case would rarely help me, and in other cases, I don't think that they provide enough value to bother. For in contracts, you can just as easily put the assertion in the function unless you need additional statements to prepare the condition to assert (which I usually don't), and the contract syntax is verbose enough that I'd prefer to not use it if I don't have to. As for out contracts, I don't bother, because I find that it's rare that I have a function where I can have a condition which is generically testable. It's very common to be able to test that specific input gives specific output but not that all output passes a particular condition. And unit tests are the place to test that specific input gives you specific output, not the out contract. So, I use unit tests _very_ heavily, but I don't use out contracts much. In principle, contracts really should be compiled in based on how the caller was compiled, not the function being called, since in contracts are really testing the caller (since it's the caller that provides the input being tested), and it also makes sense for the caller to be in control of whether the output is validated or not. This would be _really_ useful in the case of libraries, because then the library could be compiled with -release, but you'd get the contracts checked if you didn't compile your program with -release. That would be a _huge_ motivator for using contracts with libraries rather than putting the assertions inside the functions. But unfortunately, that's not how contracts are currently implemented. Also, some folks want the compiler to be able to statically examine the conditions in contracts so that it can flag stuf at complie time based on what's in the contracts. e.g. it would be great if the compiler flagged void foo(int i) in { assert(i > 42); } do { } void main() { foo(0); } and gave you a compiler error. But no has implemented anything like that, and contracts are purely runtime entities at this point. It's also been suggested that contracts be put in the documentation so that folks could see what they are and thus know what's valid and isn't rather than having to write it out in the documentation. And if that were implemented, then maybe it would be worth using contracts in some cases. So, it _may_ be the case in the future that contracts will become more useful, but right now, outside of classes, they're not all that useful. Some folks do prefer to use them though, because they prefer to have the pre and post conditions segregated out of their code. - Jonathan M Davis
Jan 27 2018
prev sibling parent reply Steven Schveighoffer <schveiguy yahoo.com> writes:
On 1/27/18 9:31 AM, Ali Çehreli wrote:
 On 01/27/2018 05:52 AM, kdevel wrote:
  > https://dlang.org/phobos/std_exception.html#enforce states:
  >
  > | Also, do not use enforce inside of contracts (i.e. inside of in and
  > out blocks
  > | and invariants), because they will be compiled out when compiling with
  > -release.
  > | Use assert in contracts.
  >
  > But assert is also ignored in release mode:
 
 The documentation is not clear. "they will be compiled out" means 
 "contracts are compiled out". So, an enforce() would disappear if it's 
 inside such a block, which should not be what the programmer wants for 
 an enforce().
There is another problem with using enforce in contracts, it throws Exceptions, whereas contracts are expected to throw Errors. The most important aspect about this is that nothrow functions can still throw Errors. So if you have a nothrow function with an in-contract that throws an Exception, compiling in release mode may is a mistake (I'm not sure if the compiler even detects this). I think the current docs (as they have been modified) are fine.
 Fixed it through the "Improve this page" link on that Phobos page:
 
    https://github.com/dlang/phobos/blob/master/std/exception.d
 
 Ali
Hm... it appears that you committed directly to the branch. Even if changing docs, you should do so with a pull request. For normal mortals, this happens automatically, but for people who have commit rights, you have to be careful to select the right thing ;) -Steve
Jan 28 2018
parent =?UTF-8?Q?Ali_=c3=87ehreli?= <acehreli yahoo.com> writes:
On 01/28/2018 11:31 AM, Steven Schveighoffer wrote:

 Fixed it through the "Improve this page" link on that Phobos page:

    https://github.com/dlang/phobos/blob/master/std/exception.d

 Ali
Hm... it appears that you committed directly to the branch. Even if changing docs, you should do so with a pull request. For normal mortals, this happens automatically, but for people who have commit rights, you have to be careful to select the right thing ;) -Steve
Guilty as charged! Seb has already brought me to my senses by email. Ali
Jan 28 2018