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

Marko Ristin-Kaufmann marko.ristin at gmail.com
Fri Sep 28 09:41:20 EDT 2018


Hi,

(Posting from work, so sorry for the short response.)

@Paul Moore <p.f.moore at gmail.com> icontract.pre/post/inv have the enabled
argument; if not enabled, the contract is ignored.

Similarly with rmdir() -- "the directory must be empty" -- but how exactly
>> am I supposed to check that?
>>
>
> Isn't that the whole point? The prose statement "the directory must be
> empty" is clear. But the exact code check isn't - and may be best handled
> by a series of unit tests, rather than a precondition.
>

I meant "check" as a user, not as a developer. As in "What did the
implementer think -- how am I supposed to check that the directory is
empty?" A la: "Dear user, if you want to rmdir, here is what you need to
check that it is indeed a dir, and here is what you need to check that it
is empty. If both checks pass, run me."

@David patching __doc__ automatically is on the short-term todo list. I
suppose we'll just add sphinx directives (:requires:, :ensures: etc.)

* Marko isn't that familiar with the codebase, so there may be better
> ways to express certain things
>

This is true :)

* Sometimes it's just plain hard to express a verbal constraint in code
>

In these cases you simply don't express it in code. Why would you? If it's
complex code, possibility that you have an error is probably equal or
higher than that your comment rots.

@pre(lambda args, result: not any(Path(arg).is_absolute() for arg in args)
> or
> (result == [pth for arg in args for pth in [Path(arg)] if
> pth.is_absolute()][-1]),
> "When several absolute paths are given, the last is taken as an anchor
> (mimicking os.path.join()’s behaviour)")
>

I'm really not familiar with the code base nor with how to write stuff nice
and succinct in python. This particular contract was hard to define because
there were no last() and no arg_is_absolute() functions.

Otherwise, it would have read:

@pre(lambda args, result: not any(arg_is_absolute(arg) for arg in args) or
result == Path(last(arg for arg in args if arg_is_absolute(arg)))

When rendered, this wouldn't look too bad to read.

@Chris

> It is still fundamentally difficult to make assertions about the file
> system as pre/post contracts. Are you becoming aware of this?
> Contracts, as has been stated multiple times, look great for
> mathematically pure functions that have no state outside of their own
> parameters and return values (and 'self', where applicable), but are
> just poor versions of unit tests when there's anything external to
> consider.
>

I never thought of these particular contracts as running in the production.
I would set them to run only in testing and only on part of the tests where
they are safe from race conditions (e.g., setting
enabled=test_pathlib.SERIAL; toggling mechanism is something I haven't
spent too much thought about either and would also need to be
discussed/implemented.).

I really thought about them as documentation, not for correctness (or at
best deeper tests during the testing in a "safe" local environment, for
example when you want to check if all the contracts also hold on situations
in *my *testsuite, not only during the test suite of pathlib).

In the end, I'm calling it the day. I really got tired in the last few
days. Standardizing contracts for python is not worth the pain. We'll
continue to develop icontract for our internal needs and keep it open
source, so anybody who's interested can have a look. Thank you all for a
very lively discussions!

Cheers,
Marko



On Fri, 28 Sep 2018 at 14:49, Paul Moore <p.f.moore at gmail.com> wrote:

> On Fri, 28 Sep 2018 at 13:23, David Mertz <mertz at gnosis.cx> wrote:
> > I agree that all the Sphinx documentation examples shown are very nice.
> Prose descriptions would often be nicer still, but the Boolean expressions
> are helpful for those unusual cases where I don't want to look at the code.
>
> I'm ambivalent about the Sphinx examples. I find the highly detailed
> code needed to express a condition fairly unreadable (and I'm an
> experienced Python programmer). For example
>
> @pre(lambda args, result: not any(Path(arg).is_absolute() for arg in args)
> or
> (result == [pth for arg in args for pth in [Path(arg)] if
> pth.is_absolute()][-1]),
> "When several absolute paths are given, the last is taken as an anchor
> (mimicking os.path.join()’s behaviour)")
>
> The only way I'd read that is by looking at the summary text - I'd
> never get the sense of what was going on from the code alone. There's
> clearly a number of trade-offs going on here:
>
> * Conditions should be short, to avoid clutter
> * Writing helper functions that are *only* used in conditions is more
> code to test or get wrong
> * Sometimes it's just plain hard to express a verbal constraint in code
> * Marko isn't that familiar with the codebase, so there may be better
> ways to express certain things
>
> But given that *all* the examples I've seen of contracts have this
> issue (difficult to read expressions) I suspect the problem is
> inherent.
>
> Another thing that I haven't yet seen clearly explained. How do these
> contracts get *run*? Are they checked on every call to the function,
> even in production code? Is there a means to turn them off? What's the
> runtime overhead of a "turned off" contract (even if it's just an
> if-test per condition, that can still add up)? And what happens if a
> contract fails - is it an exception/traceback (which is often
> unacceptable in production code such as services)? The lack of any
> clear feel for the cost of adding contracts is part of what makes
> people reluctant to use them (particularly in the face of the
> unfortunately still common assertion that "Python is slow" :-()
>
> Paul
>
-------------- next part --------------
An HTML attachment was scrubbed...
URL: <http://mail.python.org/pipermail/python-ideas/attachments/20180928/0ef802e3/attachment.html>


More information about the Python-ideas mailing list