Skip to content

Commit 61cef4e

Browse files
mathias-lang-sociomanticmdparker
authored andcommitted
DIP1006: Providing more selective control over contracts (#54)
The aim of this DIP is to provide a common approach to handle deployment of applications in non-release mode.
1 parent 9b815d5 commit 61cef4e

File tree

1 file changed

+102
-0
lines changed

1 file changed

+102
-0
lines changed

DIPs/DIP1006.md

Lines changed: 102 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,102 @@
1+
# Providing more selective control over contracts
2+
3+
| Field | Value |
4+
|-----------------|-----------------------------------------------------------------|
5+
| DIP: | DIP1006 |
6+
| RC# | 0 |
7+
| Author: | Mathias Lang - [email protected] |
8+
| Implementation: | None |
9+
| Status: | Will be set by the DIP manager (e.g. "Approved" or "Rejected") |
10+
11+
12+
## Abstract
13+
14+
A proposal to expose a way to selectively disable some of D's contract features
15+
(invariant, `in` / `out` and `assert`).
16+
17+
18+
### Links
19+
20+
Limited D1 implementation, used by Sociomantic: https://github.com/dlang/dmd/pull/6347
21+
22+
23+
## Description
24+
25+
Add a command-line switch, named `-contracts` in this proposal, which takes 4 possible values:
26+
27+
- `all`: the default, present for completeness and scripts, so one can just append it to a generated command line to enable all contracts checks.
28+
- `noinvariant`: Disable implicit `invariant` calls, but leaves function's `in` / `out` contracts and `assert` in.
29+
- `assert`: Disable `invariant` blocks and `in` / `out` contracts, but leaves `assert` in.
30+
- `none`: Disable all `invariant`, `in` and `out` contracts, and `assert`.
31+
32+
Note that the `noinvariant` value only disables implicit calls to invariant. Explicit calls can only disabled by disabling `assert`.
33+
34+
35+
### Rationale
36+
37+
#### Prelude on contracts
38+
39+
Under the broad name "Contracts", we regroup 4 of D features: `assert`, `in` contracts, `out` contracts and `invariant`.
40+
Contracts in D are a mean to do sanity checking. A contract that fails is a sign of a faulty logic in the code.
41+
Since contracts should never fail, the currently advertised approach for D programers is to use them during development,
42+
then deploy a `-release` build of the application for maximum performances.
43+
44+
Contracts naturally fit in a hierarchy, where `assert` is the most basic block (being used by others),
45+
and `invariant` is meant for expensive sanity checking. `in` and `out` contracts are located in between.
46+
47+
#### Cost of contracts
48+
49+
`assert` and `in` / `out` contracts follow a pay-for-what-you-use approach: an `assert` which is never executed is free,
50+
and a `in` or `out` contract on a function that is never called is also free of runtime overhead.
51+
52+
`invariant` stand out in that regard: they can be used on a pay-for-what-you-use basis, by using `assert(object)` (or `assert(this)`),
53+
but they are also implicitly called twice on every `public` and `protected` class method call.
54+
The call itself is not direct: the compiler inserts a call to `_d_invariant`, [which can be found in druntime](https://github.com/dlang/druntime/blob/v2.072.0/src/rt/invariant.d).
55+
The code being very simple results in the class hierarchy to be traversed completely twice (no caching is done)
56+
for every call, even for classes which do not define any invariant.
57+
58+
Profiling some real-time applications within Sociomantic showed that `_d_invariant` was the most expensive call in the application.
59+
Affected applications were using little or no invariant, but since Sociomantic code is mostly writen in an OOP style,
60+
simply disabling invariants (with no other optimization) led to 20% more throughput.
61+
62+
#### Issues with the current approach
63+
64+
Testing can be complete and it is not rare to miss a scenario that can show up any time in a production setting.
65+
In such a case, having a contract not failing where it should can lead to costs higher than the one induced by a crash of the application.
66+
Example of such case include critical data corruption and unexpected monetary spending.
67+
68+
For this reason, developers are often wary of disabling such safety features, even in production, as long as the performance cost is acceptable.
69+
What can be viewed as an acceptable performance cost is up to the end user and the code base.
70+
Any OOP-intensive code will want to get rid of `invariant` as a first step, while code more function-oriented might be more interested in disabling `in` / `out`.
71+
72+
#### Considered alternatives
73+
74+
The 4 values available to the user are voluntarily simple and hierarchical. It makes little sense to allow any contracts without enabling asserts.
75+
It would be feasible to allow `invariant` without `in` and `out` contracts, or only `out` contracts, only `in` contracts, or some other combination.
76+
Since providing all combinations would increase complexity, but doesn't yet provide an obvious advantage, it was left out of this proposal (but can be subject to another one).
77+
78+
Since this proposal was heavily motivated by the cost of invariant, an obvious alternative is to reduce said cost.
79+
However, the cost of having `invariant` enabled will never be null for builds that do not use invariants at all, which is the real motivation for this feature.
80+
81+
Finally, this functionality is already implemented in LDC via `-enable-invariants={0,1}`.
82+
Standardizing it would simplify user's life and allow tooling that deals with multiple compilers (e.g. `dub`, IDEs...) to provide this option.
83+
84+
### Breaking changes / deprecation process
85+
86+
Since this behavior is entirely opt-in, no breaking change is expected.
87+
88+
### Implementation difficulty
89+
90+
The reference front-end already segments those functionality into separate flags, hence the implementation should be trivial.
91+
92+
## Copyright & License
93+
94+
Copyright (c) 2016 by the D Language Foundation
95+
96+
Licensed under [Creative Commons Zero 1.0](https://creativecommons.org/publicdomain/zero/1.0/legalcode.txt)
97+
98+
## Review
99+
100+
Will contain comments / requests from language authors once review is complete,
101+
filled out by the DIP manager - can be both inline and linking to external
102+
document.

0 commit comments

Comments
 (0)