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

Chris Angelico rosuav at gmail.com
Wed Sep 26 04:37:51 EDT 2018


On Wed, Sep 26, 2018 at 5:51 PM Marko Ristin-Kaufmann
<marko.ristin at gmail.com> wrote:
>
> Hi Chris,
>
>> It's easy to say that they're boolean expressions. But that's like
>> saying that unit tests are just a bunch of boolean expressions too.
>> Why do we have lots of different forms of test, rather than just a big
>> fat "assert this and this and this and this and this and this"?
>> Because the key to unit testing is not "boolean expressions", it's a
>> language that can usefully describe what it is we're testing.
>> Contracts aren't just boolean expressions - they're a language (or a
>> mini-language) that lets you define WHAT the contract entails.
>
>
> Sorry, I misunderstood you. You are probably referring to knowing the terms like "preconditions, postconditions, invariants, strengthening/weakening", right? In that case, yes, I agree, I presuppose that readers are familiar with the concepts of DbC. Otherwise, of course, it makes no sense to use DbC if you assume nobody could actually figure out what it is :).
>

Let's say you want to define a precondition and postcondition for this function:

def fibber(n):
    return n < 2 ? n : fibber(n-1) + fibber(n-2)

What would you specify? Can you say, as a postcondition, that the
return value must be a Fibonacci number? Can you say that, for any 'n'
greater than about 30, the CPU temperature will have risen? How do you
describe those as boolean expressions? The art of the contract depends
on being able to adequately define the conditions.

>
> However, contracts can be useful when testing the GUI -- often it is difficult to script the user behavior. What many people do is record a session and re-play it. If there is a bug, fix it. Then re-record. While writing unit tests for GUI is hard since GUI changes rapidly during development and scripting formally the user behavior is tedious, DbC might be an alternative where you specify as much as you can, and then just re-run through the session. This implies, of course, a human tester.
>

That doesn't sound like the function's contract. That sounds like a
test case - of which you would have multiple, using different
"scripted session" inputs and different outputs (some of success, some
of expected failure).

> Here is my try at the contracts. Assuming that there is a list of figures and that they have a property "displayed" and that "State.blocked" global variable refers to whether the interface is blocked or not::
> @post(lambda: all(figure.displayed for figure in figures)
> @post(lambda: not ipython.in_pylab_mode() or not State.blocked)
> @post(lambda: not interactive() or State.blocked)
> matplotlib.pyplot.show()
>

There is no such thing as "State.blocked". It blocks. The function
*does not return* until the figure has been displayed, and dismissed.
There's no way to recognize that inside the function's state.

Contracts are great when every function is 100% deterministic and can
maintain invariants and/or transform from one set of invariants to
another. Contracts are far less clear when the definitions are
muddier.

ChrisA


More information about the Python-ideas mailing list