[Python-ideas] Why is design-by-contracts not widely adopted?

Marko Ristin-Kaufmann marko.ristin at gmail.com
Tue Sep 25 13:18:49 EDT 2018


Hi Robert,

You'll lose folks attention very quickly when you try to tell folk
> what they do and don't understand.


I apologize if I sounded offending, that was definitely not my intention. I
appreciate that you addressed that.

I suppose it's cultural/language issue and the wording was probably
inappropriate. Please let me clarify what I meant: there was a
misconception as DbC was reduced to a tool for testing, and, in a separate
message, reduced to type-checks at runtime. These are clearly
misconceptions, as DbC (as origianally proposed by Hoare and later
popularized by Meyer) include other relevant aspects which are essential
and hence can not be overseen or simply ignored. If we are arguing about
DbC without these aspects then we are simply falling pray to a straw-man
fallacy.

Claiming that DbC annotations will improve the documentation of every
> single library on PyPI is an extraordinary claim, and such claims
> require extraordinary proof.


I don't know what you mean by "extraordinary" claim and "extraordinary"
proof, respectively. I tried to show that DbC is a great tool and far
superior to any other tools currently used to document contracts in a
library, please see my message
https://groups.google.com/d/msg/python-ideas/dmXz_7LH4GI/5A9jbpQ8CAAJ. Let
me re-use the enumeration I used in the message and give you a short
summary.

The implicit or explicit contracts are there willy-nilly. When you use a
module, either you need to figure them out using trial-and-error or looking
at the implementation (4), looking at the test cases and hoping that they
generalize (5), write them as doctests (3) or write them in docstrings as
human text (2); or you write them formally as explicit contracts (1).

I could not identify any other methods that can help you with expectations
when you call a function or use a class (apart from formal methods and
proofs, which I omitted as they seem too esoteric for the current
discussion).


*Given that: *
* There is no other method for representing contracts,
* people are trained and can read formal statements and
* there is tooling available to write, maintain and represent contracts in
a nice way

I see formal contracts (1) as a superior tool. The deficiencies of other
approaches are:
2) Comments and docstrings inevitably rot and get disconnected from the
implementation in my and many other people's experience and studies.
3) Doctests are much longer and hence more tedious to read and maintain,
they need extra text to signal the intent (is it a simple test or an
example how boundary conditions are handled or ...). In any non-trivial
case, they need to include even the contract itself.
4) Looking at other people's code to figure out the contracts is tedious
and usually difficult for any non-trivial function.
5) Test cases can be difficult to read since they include much broader
testing logic (mocking, set up). Most libraries do not ship with the test
code. Identifying test cases which demonstrate the contracts can be
difficult.

*Any* function that is used by multiple developers which operates on the
restricted range of input values and gives out structured output values
benefits from contracts (1) since the user of the function needs to figure
them out to properly call the function and handle its results correctly. I
assume that every package on pypi is published to be used by wider
audience, and not the developer herself. Hence every package on pypi would
benefit from formal contracts.

Some predicates are hard to formulate, and we will never be able to
formally write down *all* the contracts. But that doesn't imply for me to *not
use contracts at all* (analogously, some functionality is untestable, but
that doesn't mean that we don't test what we can).

I would be very grateful if you could point me where this exposition is
wrong (maybe referring to my original message,
https://groups.google.com/d/msg/python-ideas/dmXz_7LH4GI/5A9jbpQ8CAAJ,
which I spent more thought on formulating).

So far, I was not confronted against nor read on the internet a plausible
argument against formal contracts (the only two exceptions being lack of
tools and less-skilled programmers have a hard time reading formal
statements as soon as they include boolean logic and quantifiers). I'm
actively working on the former, and hope that the latter would improve with
time as education in computer sciences improves.

Another argument, which I did read often on internet, but don't really
count is that quality software is not a priority and most projects hence
dispense of documentation or testing. This should, hopefully, not apply to
public pypi packages and is highly impractical for any medium-size project
with multiple developers (and very costly in the long run).

I can think of many libraries where necessary pre and post conditions
> (such as 'self is still locked') are going to be noisy, and at risk of
> reducing comprehension if the DbC checks are used to enhance/extended
> documentation.


It is up to the developer to decide which contracts are enforced during
testing, production or displayed in the documentation (you can pick the
subset of the three, it's not an exclusion). This feature ("enabled"
argument to a contract) has been already implemented in the icontract
library.

Some of the examples you've been giving would be better expressed with
a more capable type system in my view (e.g. Rust's), but I have no
good idea about adding that into Python  :/.

I don't see how type system would help regardless how strict it would be?
Unless *each *input and *each *output represent a special type, which would
be super confusing as soon as you would put them in the containers and have
to struggle with invariance, contravariance and covariance. Please see
https://github.com/rust-lang/rfcs/issues/1077 for a discussion about
introducing DbC to Rust. Unfortunately, the discussion about contracts in
Rust is also based on misconceptions (*e.g., *see
https://github.com/rust-lang/rfcs/issues/1077#issuecomment-94582917) --
there seems to be something wrong in the way anybody proposing DbC exposes
contracts to the wider audience and miss to address these issues in a good
way. So most people just react instinctively with "80% already covered with
type systems" / "mere runtime type checks, use assert" and "that's only an
extension to testing, so why bother" :(.

I would now like to answer Hugh and withdraw from the discussion pro/contra
formal contracts unless there is a rational, logical argument disputing the
DbC in its entirety (not in one of its specific aspects or as a
misconception/straw-man). A lot has been already said, many articles have
been written (I linked some of the pages which I thought were short & good
reads and I would gladly supply more reading material). I doubt I can find
a better way to contribute to the discussion.

Cheers,
Marko


On Tue, 25 Sep 2018 at 10:01, Robert Collins <robertc at robertcollins.net>
wrote:

> On Mon, 24 Sep 2018 at 19:47, Marko Ristin-Kaufmann
> <marko.ristin at gmail.com> wrote:
> >
> > Hi,
> >
> > Thank you for your replies, Hugh and David! Please let me address the
> points in serial.
> >
> > Obvious benefits
> > You both seem to misconceive the contracts. The goal of the
> design-by-contract is not reduced to testing the correctness of the code,
> as I reiterated already a couple of times in the previous thread. The
> contracts document formally what the caller and the callee expect and need
> to satisfy when using a method, a function or a class. This is meant for a
> module that is used by multiple people which are not necessarily familiar
> with the code. They are not a niche. There are 150K projects on pypi.org.
> Each one of them would benefit if annotated with the contracts.
>
> You'll lose folks attention very quickly when you try to tell folk
> what they do and don't understand.
>
> Claiming that DbC annotations will improve the documentation of every
> single library on PyPI is an extraordinary claim, and such claims
> require extraordinary proof.
>
> I can think of many libraries where necessary pre and post conditions
> (such as 'self is still locked') are going to be noisy, and at risk of
> reducing comprehension if the DbC checks are used to enhance/extended
> documentation.
>
> Some of the examples you've been giving would be better expressed with
> a more capable type system in my view (e.g. Rust's), but I have no
> good idea about adding that into Python  :/.
>
> Anyhow, the thing I value most about python is its pithyness: its
> extremely compact, allowing great developer efficiency, but the cost
> of testing is indeed excessive if the tests are not structured well.
> That said, its possible to run test suites with 10's of thousands of
> tests in only a few seconds, so there's plenty of headroom for most
> projects.
>
> -Rob
>
-------------- next part --------------
An HTML attachment was scrubbed...
URL: <http://mail.python.org/pipermail/python-ideas/attachments/20180925/0cc936ba/attachment-0001.html>


More information about the Python-ideas mailing list