www.digitalmars.com         C & C++   DMDScript  

digitalmars.D - Why no contracts for release build?

reply Andre <andre s-e-a-p.de> writes:
Hi,
I currently think about whether or not contracts should be available
in release builds.

Assuming a small example, you have an account class with a deposit 
method, the input parameter must always be > 0.

void deposit(int amount)
in
{
   enforce(amount > 0);
}
body
{
   this.amount += amount;
}

If in release build the Contracts sections is removed, this means, I 
also need to add in addition in another place the enforce method. 
Otherwise in the productive scenario, this coding isn't secure anymore. 
This leads to code duplication.

I think Contracts are not a feature solely for unittests, they are a
fundamental part of classes/interfaces and theirfore should be available
in all builds.

What do you think?

Kind regards
André
Jun 03 2014
next sibling parent "Dicebot" <public dicebot.lv> writes:
Contracts are not supposed to be use for error checking / input 
validation. Quoting docs for enforce: "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. "

Contracts are supposed to verify that there are no fundamental 
flaws in internal logic of the program which will immediately pop 
up in test / debug runs. This may imply very expensive sanity 
checks that are not welcome in release builds for performance 
reasons.

In your case you should simply move `enforce` to the function 
body and remove contract.
Jun 03 2014
prev sibling next sibling parent reply Jonathan M Davis via Digitalmars-d <digitalmars-d puremagic.com> writes:
On Tue, 03 Jun 2014 16:29:20 +0200
Andre via Digitalmars-d <digitalmars-d puremagic.com> wrote:

 Hi,
 I currently think about whether or not contracts should be available
 in release builds.

 Assuming a small example, you have an account class with a deposit
 method, the input parameter must always be > 0.

 void deposit(int amount)
 in
 {
    enforce(amount > 0);
 }
 body
 {
    this.amount += amount;
 }

 If in release build the Contracts sections is removed, this means, I
 also need to add in addition in another place the enforce method.
 Otherwise in the productive scenario, this coding isn't secure
 anymore. This leads to code duplication.

 I think Contracts are not a feature solely for unittests, they are a
 fundamental part of classes/interfaces and theirfore should be
 available in all builds.

 What do you think?

Contracts are specifically intended for validating the input and output of a function with assertions. So, they're going to go away in any build that does not have assertions enabled. Contracts are very much the wrong place to use enforce. enforce throws an Exception and does not get compiled out. It is intended for error-handling rather than for validating the correctness of your code. - Jonathan M Davis
Jun 03 2014
parent Andre <andre s-e-a-p.de> writes:
Am 03.06.2014 19:13, schrieb Jonathan M Davis via Digitalmars-d:
 On Tue, 03 Jun 2014 16:29:20 +0200
 Andre via Digitalmars-d <digitalmars-d puremagic.com> wrote:

 Hi,
 I currently think about whether or not contracts should be available
 in release builds.

 Assuming a small example, you have an account class with a deposit
 method, the input parameter must always be > 0.

 void deposit(int amount)
 in
 {
     enforce(amount > 0);
 }
 body
 {
     this.amount += amount;
 }

 If in release build the Contracts sections is removed, this means, I
 also need to add in addition in another place the enforce method.
 Otherwise in the productive scenario, this coding isn't secure
 anymore. This leads to code duplication.

 I think Contracts are not a feature solely for unittests, they are a
 fundamental part of classes/interfaces and theirfore should be
 available in all builds.

 What do you think?

Contracts are specifically intended for validating the input and output of a function with assertions. So, they're going to go away in any build that does not have assertions enabled. Contracts are very much the wrong place to use enforce. enforce throws an Exception and does not get compiled out. It is intended for error-handling rather than for validating the correctness of your code. - Jonathan M Davis

As I known that assertions are only for unittest purposes I hoped, if I use enforce, this statements will not be removed in release build and will still be executed - wrong. I see, the idea of contracts in D differs to the idea of contracts e.g. in Java (http://c4j-team.github.io/C4J/ Here contracts are used for unittest but also for the productive code in release builds. I thought about writing a Contracts library, which works similiar to C4J but I see no chance to solve this issue without AST. Kind regards André
Jun 03 2014
prev sibling next sibling parent Jonathan M Davis via Digitalmars-d <digitalmars-d puremagic.com> writes:
On Tue, 03 Jun 2014 21:11:52 +0200
Andre via Digitalmars-d <digitalmars-d puremagic.com> wrote:

 As I known that assertions are only for unittest purposes I hoped,
 if I use enforce, this statements will not be removed in release build
 and will still be executed - wrong.

 I see, the idea of contracts in D differs to the idea of contracts
 e.g. in Java (http://c4j-team.github.io/C4J/
 Here contracts are used for unittest but also for the productive code
 in release builds.

I don't know what C4J does, but the entire purpose of having in and out contracts in D is to support Design by Contract, so they're intended to catch bugs where the "contract" of a function is violated (i.e. where it requires that the input satisfy certain criteria and guarantees certain criteria for its output). It has nothing to do with error handling whatsoever. If anything, design by contract is the antithesis of error handling, because it's considered an outright bug if a contract is violated. As such, it really doesn't make sense to use the in or out blocks for anything other than assertions. And honestly, I don't see how you would gain anything if you could. Aside from virtual functions, there is no difference between asserting at the beginning of a function or in the in block, and there is no difference between asserting in the out block and asserting in a scope(success) statement which is put at the beginning of the function. The only place where the in and out blocks actually gain you anything is that in a virtual function their success or failure is effectively &&ed or ||ed with those of the other virtual functions in the inheritance tree (because the in contracts only have to be as strict as the contracts in the most derived function, and the out contracts have to be as strict as the contracts in all of the virtual functions in the inheritance tree). It's that extra bit of logic for classes where the runtime catches and ignores AssertErrors where appropriate that actually makes it so that the in and out blocks actually buy you anything. And since none of that would actually apply to exceptions, I don't see how using in and out blocks would actually buy you anything when using exceptions. As it is, it doesn't buy you much when using assertions. - Jonathan M Davis
Jun 03 2014
prev sibling next sibling parent reply "Sean Kelly" <sean invisibleduck.org> writes:
On Tuesday, 3 June 2014 at 14:29:19 UTC, Andre wrote:
 Hi,
 I currently think about whether or not contracts should be 
 available in release builds.

...
 I think Contracts are not a feature solely for unittests, they 
 are a fundamental part of classes/interfaces and theirfore 
 should be available in all builds.

I think the problem is that "release" is a misnomer, because the presence of contracts has nothing to do with whether you're deploying a test or release build. For all the talk of how we should be profiling our code to find the trouble spots instead of prematurely optimizing, the release flag, by virtue of its name, exists as a giant red button we're all expected to press for "performance" or whatever before deploying our software for use in the first instance where safety actually matters. As for the idea that contracts simply aid in finding logic errors during testing... for testing to have any validity the test must be performed on the same build that will be released to the public. And the idea that testing will ever find all the problems that might occur in the field is laughable. In short, pretend "release" says something like "unchecked" and think hard before actually setting it in real code.
Jun 03 2014
parent reply Andre <andre s-e-a-p.de> writes:
Am 03.06.2014 23:43, schrieb Sean Kelly:
 I think the problem is that "release" is a misnomer, because the
 presence of contracts has nothing to do with whether you're
 deploying a test or release build.  For all the talk of how we
 should be profiling our code to find the trouble spots instead of
 prematurely optimizing, the release flag, by virtue of its name,
 exists as a giant red button we're all expected to press for
 "performance" or whatever before deploying our software for use
 in the first instance where safety actually matters.

 As for the idea that contracts simply aid in finding logic errors
 during testing... for testing to have any validity the test must
 be performed on the same build that will be released to the
 public.  And the idea that testing will ever find all the
 problems that might occur in the field is laughable.

 In short, pretend "release" says something like "unchecked" and
 think hard before actually setting it in real code.

Yes you are right. For my product "released" to customer, as business application developer, I am more focused on safety and less on performance. If in any case a customer is doing s.th which can be caught by contracts then it should be caught. Therefore the release switch is really dangerous. What I really want is a switch "stable", which contains all safety relevant features like Contracts/Asserts and so on. But this build should exclude debug information etc. I currently wonder what is included by adding no switch to DMD?
 dmd main

Kind regards André
Jun 04 2014
next sibling parent "Martin Krejcirik" <mk-junk i-line.cz> writes:
 What I really want is a switch "stable", which contains all 
 safety relevant features like Contracts/Asserts and so on. But

Just compile _without_ -release -debug -g -unittest options.
Jun 04 2014
prev sibling parent reply "Martin Krejcirik" <mk-junk i-line.cz> writes:
On Wednesday, 4 June 2014 at 13:48:04 UTC, Andre wrote:
 I currently wonder what is included by adding no switch to DMD?

default (no switch) = asserts, contracts, boundscheck=all -debug = include code marked with debug keyword -unittest = include unittests -g = include debug info -release = do not include asserts, contracs, boundscheck=safeonly, some switch optimizations -boundscheck option can override -release option for turning on or off all bounds checking (there is deprecated -noboundscheck in 2.065 or earlier)
Jun 04 2014
parent Andre <andre s-e-a-p.de> writes:
Am 04.06.2014 16:23, schrieb Martin Krejcirik:
 On Wednesday, 4 June 2014 at 13:48:04 UTC, Andre wrote:
 I currently wonder what is included by adding no switch to DMD?

default (no switch) = asserts, contracts, boundscheck=all -debug = include code marked with debug keyword -unittest = include unittests -g = include debug info -release = do not include asserts, contracs, boundscheck=safeonly, some switch optimizations -boundscheck option can override -release option for turning on or off all bounds checking (there is deprecated -noboundscheck in 2.065 or earlier)

thanks a lot for these informations, exactly what I need. Kind regards André
Jun 04 2014
prev sibling parent "Kagamin" <spam here.lot> writes:
On Tuesday, 3 June 2014 at 14:29:19 UTC, Andre wrote:
 Hi,
 I currently think about whether or not contracts should be 
 available
 in release builds.

Use release build only if you proved the code is 100% correct. It's hardly useful in realistic scenarios. See the recently reported buffer overflow bug in druntime which would be otherwise caught twice by asserts: https://issues.dlang.org/show_bug.cgi?id=12848
Jun 04 2014