[Python-Dev] Introduction

Terence Way terry@wayforward.net
Thu, 29 May 2003 10:53:16 -0400


On Wednesday, May 28, 2003, at 04:55  PM, Peter Jones wrote:

> What if the docstring fails to parse?  I have to be listening to 
> stderr to
> know that it didn't work.  I then have to parse the message from 
> stderr to
> figure out which function didn't work, and finally I have to somehow 
> mark
> this function as not compliant, and ignore whatever results I get.
>
I probably would have figured that out too, eventually... :-)  More on
this further down, when I talk about how to enable docstring testing.

> That being said, you still haven't explained *why* contracts belong in
> docstrings (or in documentation in general).  They are executable code;
> why not treat them as such?
>
Okay, the whole docstring vs syntax thing, and I'm going to quote
liberally from Bertrand Meyer's Object Oriented Software Construction,
1st edition, 7.9 Using Assertions.

There are four main reasons for adding contracts to code:
"""
* Help in writing correct software.
* Documentation aid.
* Debugging tool.
* Support for software fault tolerance.

[...]

The second use is essential in the production of reusable software
elements and, more generally, in organizing the interfaces of
modules in large software systems.  Preconditions, postconditions,
and class invariants provide potential clients of a module with
crucial information about the services offered by the module, expressed
in a concise and precise form.  No amount of verbose documentation can
replace a set of carefully expressed assertions.
"""

I really like Extreme Programming's cut-to-the-bone approach: there
are only two things worth knowing about the code: *what* it does and
*how* it does it.  In XP, what the code does can be inferred from
test cases; how it does it from the source code.  And if you can't
read the code, you have no business talking about how the software
does what it does anyway.

With contracts, I want to move the knowledge of *what* the code does
from the test cases back into the programming documentation.  It
is merely a bonus feature that this documentation can be executed.

When I was learning Python (um, not too long ago) the epiphany of
what this language was all about hit me when I saw the 'doctest'
module.  We're *always* using examples as clear, concise ways to
describe what our code does, but we're all guilty of letting those
examples get out-of-date.  Doctest can crawl into our software
deep enough to keep us honest about our documentation.  Contracts
extend this so it's not just about the basic sample cases, but
about the entire state space that a function supports... "Here be
dragons" but over there be heap-based priority queues.

>> self.note(): where *is* the documentation on how to enable the
>> behavior.
>
> I suspect we have to know this before we can know which way is easier.
>
Now that I've come out as a doctest fanboy, it should be no surprise
that contracts are enabled like this:
     import contracts, mymodule
     contracts.checkmod(mymodule)

The checkmod side effect is that all functions within mymodule are
replaced by auto-generated checking functions.

And now I think I'm clear in my own mind about backwards-
compatibility with informal 'pre:' docstrings... a programmer
doesn't run checkmod unless she's sure that all docstring
contracts are valid.  Syntax error exceptions will be passed
through to the checkmod caller.

Cheers!