Hi Terry,

I would encourage you to read all the messages on the thread. The points you raised were actually already discussed:
* Using formal contracts in the code does not imply that you must specify all the contracts; you specify what you consider meaningful.
* Distinction of result/process (the example that was already discussed was related to GUIs and pathlib standard library)

> b)//If you write contracts in text, they will become stale over time

Not true for good docstrings.  We very seldom change the essential
meaning of public functions.

In my team, we have a stale docstring once every two weeks or even more often. If it weren't for doctests and contracts, I could imagine we would have them even more often :)

I suppose good docstrings require many reviewers and slow refactoring processes. Our public interfaces are changing daily and there is one reviewer per pull request. If github/bitbucket allowed for better highlighting of docstrings in code reviews (e.g., if it highlighted the docstring of every function that changed), the miss rate would be probably lower. I'm always happy to hear other experiences how people dealt with requirements changing at a fast pace and how they dealt with code rot in a team of limited size and time resources.

I agree with you that a good docstring is not stale by definition. I have just never experienced a team that had good docstrings in my career.


On Sun, 7 Oct 2018 at 22:25, Terry Reedy <tjreedy@udel.edu> wrote:
On 9/24/2018 3:46 AM, Marko Ristin-Kaufmann wrote:

I am responding to your request "Please do point me to what is not
obvious to you".  I think some of your claims are not only not obvious,
but are wrong.  I have read some (probably less than half) of the
responses and avoid saying what I know others have covered adequately.

A mathematical function is defined or specified by a input domain,
output range, and a mapping from inputs to outputs.  The mapping can be
defined either by an explicit listing of input-output pairs or by a rule
specifying either a) the process, what is done to inputs to produce
outputs or, b) the result, how the output relates to the input.


defines contracts as "precise (legally unambiguous) specifications" (5.2
Business Contracting/Sub-contracting Metaphor)  It is not obvious to me
that the metaphor of contracts adds anything worthwhile to the idea of

1. Only a small sliver of human interactions are governed by formal
legal contracts read, understood, and agreed to by both (all) parties.

2. The idealized definition is naive in practice.  Most legal contracts,
unlike the example in the link article, are written in language that
most people cannot read.  Many contracts are imprecise and legally
ambiguous, which is why we have contract dispute courts.  And even then,
the expense means that most people who feel violated in a transaction do
not use courts.

Post-conditions specify a function by result.  I claim that this is not
always sensible.  I said above that functions may be specified by
process rather than result.  Ironically, the contract metaphor
reinforces my claim.  Many contracts, such as in teaching and medicine,
only specify process and explicitly disclaim any particular result of
concern to the client.

> b)//If you write contracts in text, they will become stale over time

Not true for good docstrings.  We very seldom change the essential
meaning of public functions.

How has "Return the sine of x (measured in radians).", for math.sin,
become stale?  Why would it ever?  What formal executable post condition
would help someone who does not understand 'sine', or 'sine of x'?  The
function is only useful for someone who either understands 'sine' or is
copying a formula written elsewhere without needing to understand it.

Or consider "Stable sort *IN PLACE*." for list.sort.  A formal
executable post-condition for this *can* be written.  But for someone
who understands the words 'stable', 'sort', and 'in place', this compact
English post condition is much more readable than any formal version
could be.  More over, that addition of 'stable', when we were ready to
do so, did not make "Sort *IN PLACE*" stale in any sense of being wrong.

I said above that functions definitions and contracts can specify the
process rather than the result.  For functions, the code is the process,
and the code may then be the specification and the contract.  For instance,

def append_first(seq):
     "Append seq[0] to seq."

So seq must have a first element accessed as seq[0] and an append method
that accepts the first element as an argument.  One might guess the
minimal body.

     return seq.append(seq[0])

The pre-condition here is that the return value can be calculated as
specified.  Whenever this is true, python is already testing
pre-conditions, as efficiently as possible.  We could elaborate the body as

         return seq.append(seq[0])
     except Exception as e:
         raise ValueError('raised ' + repr(e)[0])

and add 'Raise ValueError with explanation on bad input' to the doc string.

If the domain were restricted to lists, we could write a post-condition,
and use that in a list-based unittest.  However, it likely be less
readable than the docstring, and would execute in O(n) time (for an O(1)
function).  The latter is acceptable for unittests, which will use short
tests, but not for production.  But with duck-typing, no post condition
is possible.  Neither is a generic unittest.  The code *is* the
contract.  This is generally true of duck-typed Python code.

Terry Jan Reedy

Python-ideas mailing list
Code of Conduct: http://python.org/psf/codeofconduct/