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

Marko Ristin-Kaufmann marko.ristin at gmail.com
Tue Sep 25 03:28:08 EDT 2018


Hi Steve and others,
After some thinking, I'm coming to a conclusion that it might be wrong to
focus too much about how the contracts are written -- as long as they are
formal, easily  transformable to another representation and fairly
maintainable.

Whether it's with a lambda, without, with "args" or "a", with "old" or "o"
-- it does not matter that much as long as it is pragmatic and not
something crazy complex. This would also mean that we should not add
complexity (*e.g., *by adding macros) and limit the magic as much as
possible.

It is actually much more important in which form they are presented to the
end-user. I already made an example with sphinx-icontract in a message
before -- an improved version might use mathematical symbols (*e.g., *replace
all() with ∀, replace len() with |.|, nicely use subscripts for ranges, use
case distinction with curly bracket "{" instead of if.. else ..., etc.).
This would make them even shorter and easier to parse. Let me iterate the
example I already pasted in the thread before to highlight what I have in
mind:
packagery.resolve_initial_paths(*initial_paths*)

Resolve the initial paths of the dependency graph by recursively adding *.py
files beneath given directories.
Parameters:

*initial_paths* (List[Path]) – initial paths as absolute paths
Return type:

List[Path]
Returns:

list of initial files (*i.e.* no directories)
Requires:

   - all(pth.is_absolute() for pth in initial_paths)

Ensures:

   - all(pth in result for pth in initial_paths if pth.is_file()) (Initial
   files also in result)
   - len(result) >= len(initial_paths) if initial_paths else result == []
   - all(pth.is_absolute() for pth in result)
   - all(pth.is_file() for pth in result)


The contracts need to extend __doc__ of the function accordingly (and the
contracts in __doc__ also need to reflect the inheritance of the
contracts!), so that we can use help().

There should be also a plugin for Pycharm, Pydev, vim and emacs to show the
contracts in an abbreviated and more readable form in the code and only
show them in raw form when we want to edit them (*i.e., *when we move
cursor over them). I suppose inheritance of contracts needs to be reflected
in quick-inspection windows, but not in the code view.

Diffs and github/bitbucket/... code reviews might be a bit cumbersome since
they enforce the raw form of the contracts, but as long as syntax is
pragmatic, I don't expect this to be a blocker.

Is this a sane focus?

Cheers,
Marko

On Tue, 25 Sep 2018 at 08:18, Marko Ristin-Kaufmann <marko.ristin at gmail.com>
wrote:

> Hi Steve,
> Thanks a lot for pointing us to macropy -- I was not aware of the library,
> it looks very interesting!
>
> Do you have any experience how macropy fit with current IDEs and static
> linters (pylint, mypy)? I fired up pylint and mypy on the sample code from
> their web site, played a bit with it and it seems that they go along well.
>
> I'm also a bit worried how macropy would work out in the libraries
> published to pypi -- imagine if many people start using contracts.
> Suddenly, all these libraries would not only depend on a contract library
> but on a macro library as well. Is that something we should care about?
> Potential dependency hell? (I already have a bad feeling about making
> icontract depend on asttokens and considerin-lining asttokens into
> icontract particularly for that reason).
>
> I'm also worried about this one (from
> https://macropy3.readthedocs.io/en/latest/overview.html):
>
>> Note that this means *you cannot use macros in a file that is run
>> directly*, as it will not be passed through the import hooks.
>
>
> That would make contracts unusable in any stand-alone script, right?
>
> Cheers,
> Marko
>
> On Tue, 25 Sep 2018 at 06:56, Stephen J. Turnbull <
> turnbull.stephen.fw at u.tsukuba.ac.jp> wrote:
>
>> Barry Scott writes:
>>
>>  > > @requires(lambda self, a, o: self.sum == o.sum - a.amount)
>>  > > def withdraw(amount: int) -> None:
>>  > >     ...
>>  > >
>>  > > There is this lambda keyword in front, but it's not too bad?
>>  >
>>  > The lambda smells of internals that I should not have to care about
>>  > being exposed.
>>  > So -1 on lambda being required.
>>
>> If you want to get rid of the lambda you can use strings and then
>> 'eval' them in the condition.  Adds overhead.
>>
>> If you want to avoid the extra runtime overhead of parsing
>> expressions, it might be nice to prototype with MacroPy.  This should
>> also allow eliminating the lambda by folding it into the macro (I
>> haven't used MacroPy but it got really good reviews by fans of that
>> kind of thing).  It would be possible to avoid decorator syntax if you
>> want to with this implementation.
>>
>> I'm not sure that DbC is enough of a fit for Python that it's worth
>> changing syntax to enable nice syntax natively, but detailed reports
>> on a whole library (as long as it's not tiny) using DbC with a nice
>> syntax (MacroPy would be cleaner, but I think it would be easy to "see
>> through" the quoted conditions in an eval-based implementation) would
>> go a long way to making me sit up and take notice.  (I'm not
>> influential enough to care about, but I suspect some committers would
>> be impressed too.  YMMV)
>>
>> Steve
>> _______________________________________________
>> Python-ideas mailing list
>> Python-ideas at python.org
>> https://mail.python.org/mailman/listinfo/python-ideas
>> Code of Conduct: http://python.org/psf/codeofconduct/
>>
>
-------------- next part --------------
An HTML attachment was scrubbed...
URL: <http://mail.python.org/pipermail/python-ideas/attachments/20180925/f3767b00/attachment.html>


More information about the Python-ideas mailing list