<div dir="ltr"><div dir="ltr"><div dir="ltr"><div dir="ltr"><div dir="ltr"><div dir="ltr"><div dir="ltr"><div dir="ltr"><div dir="ltr"><div dir="ltr"><div dir="ltr"><div dir="ltr"><div dir="ltr"><div dir="ltr"><div dir="ltr"><div dir="ltr"><div dir="ltr"><div dir="ltr"><div dir="ltr"><div dir="ltr"><div dir="ltr"><div dir="ltr"><div dir="ltr"><div>Hi,<br><br></div>Thank you for your replies, Hugh and David! Please let me address the points in serial.<br></div><div dir="ltr"><br><div><b>Obvious benefits</b><br></div></div><div>You both seem to misconceive the contracts. The goal of the design-by-contract is not reduced to testing the correctness of the code, as I reiterated already a couple of times in the previous thread. The contracts document <i>formally</i> what the caller and the callee expect and need to satisfy when using a method, a function or a class. This is meant for a module that is used by multiple people which are not necessarily familiar with the code. They are <i>not </i>a niche. There are 150K projects on <a href="http://pypi.org">pypi.org</a>. Each one of them would benefit if annotated with the contracts.<br><br>Please do re-read my previous messages on the topic a bit more attentively. These two pages I also found informative and they are quite fast to read (<15 min):<br><a href="https://www.win.tue.nl/~wstomv/edu/2ip30/references/design-by-contract/index.html">https://www.win.tue.nl/~wstomv/edu/2ip30/references/design-by-contract/index.html</a><br><a href="https://gleichmann.wordpress.com/2007/12/09/test-driven-development-and-design-by-contract-friend-or-foe/">https://gleichmann.wordpress.com/2007/12/09/test-driven-development-and-design-by-contract-friend-or-foe/</a><br><br>Here is a quick summary of the argument. <br><br></div>When you are documenting a method you have the following options:<br><div>1) Write preconditions and postconditions formally and include them automatically in the documentation (<i>e.g., </i>by using icontract library). <br></div><div>2) Write precondtions and postconditions in docstring of the method as human text.<br></div><div>3) Write doctests in the docstring of the method.<br></div><div>4) Expect the user to read the actual implementation.<br></div><div>5) Expect the user to read the testing code.<br></div><div dir="ltr"><br></div><div>Here is what seems obvious to me. <i>Please do point me to what is not obvious to you</i> because that is the piece of puzzle that I am missing (<i>i.e. </i>why this is not obvious and what are the intricacies). I enumerated the statements for easier reference:<br><br></div><div>a) Using 1) is the only option when you have to deal with inheritance. Other approaches can no do that <i>without much repetition </i>in practice<i>.<br></i></div><div><br>b)<i> </i>If you write contracts in text, they will become stale over time (<i>i.e. </i>disconnected from the implementation and <i>plain wrong and misleading</i>). It is a common problem that the comments rot over time and I hope it does not need further argument (please let me know if you really think that the comments <i>do not rot</i>).<br></div><div><br>c) Using 3), doctests, means that you need mocking as soon as your method depends on non-trivial data structures. Moreover, if the output of the function is not trivial and/or long, you actually need to write the contract (as postcondition) just <i>after </i>the call in the doctest. Documenting preconditions includes writing down the error that will be thrown. Additionally, you need to write that what you are documenting actually also holds for all other examples, not just for this particular test case (<i>e.g.</i>, in human text as a separate sentence before/after the doctest in the docstring).<br></div><div><br>d) Reading other people's code in 4) and 5) is not trivial in most cases and requires a lot of attention as soon as the method includes calls to submethods and functions. This is impractical in most situation<i>s </i>since <i>most code is non-trivial to read</i> and is subject to frequent changes.<br><br>e) Most of the time, 5) is not even a viable option as the testing code is not even shipped with the package and includes going to github (if the package is open-sourced) and searching through the directory tree to find the test. This forces every user of a library to get familiar with the <i>testing code </i>of the library. <br><br>f) 4) and 5) are <i>obviously</i> a waste of time for the user -- please do explain why this might not be the case. Whenever I use the library, I do not expect to be forced to look into its test code and its implementation. I expect to read the documentation and just use the library if I'm confident about its quality. I have rarely read the implementation of the standard libraries (notable exceptions in my case are ast and subprocess module) or any well-established third-party library I frequently use (numpy, opencv, sklearn, nltk, zmq, lmdb, sqlalchemy). If the documentation is not clear about the contracts, I use trial-and-error to figure out the contracts myself. This again is <i>obviously</i> a waste of time of the <i>user </i>and it's far easier to read the contracts directly than use trial-and-error<i>.<br></i></div><div><br></div><div><b>Contracts are difficult to read.<br></b></div><div>David wrote:<br><blockquote class="gmail_quote" style="margin:0px 0px 0px 0.8ex;border-left:1px solid rgb(204,204,204);padding-left:1ex">To me, as I've said, DbC imposes a very large cost for both writers and readers of code.<br></blockquote><div><br></div><div>This is again something that eludes me and I would be really thankful if you could clarify. Please consider for an example, pypackagery (<a href="https://pypackagery.readthedocs.io/en/latest/packagery.html">https://pypackagery.readthedocs.io/en/latest/packagery.html</a>) and the documentation of its function resolve_initial_paths:<br><dl class="gmail-function"><dt id="gmail-packagery.resolve_initial_paths">
<code class="gmail-descclassname">packagery.</code><code class="gmail-descname">resolve_initial_paths</code><span class="gmail-sig-paren">(</span><em>initial_paths</em><span class="gmail-sig-paren">)</span></dt><dd><p>Resolve the initial paths of the dependency graph by recursively adding <code class="gmail-docutils gmail-literal gmail-notranslate"><span class="gmail-pre">*.py</span></code> files beneath given directories.</p>
<table class="gmail-docutils gmail-field-list" frame="void" rules="none">
<colgroup><col class="gmail-field-name">
<col class="gmail-field-body">
</colgroup><tbody valign="top">
<tr class="gmail-field-odd gmail-field"><th class="gmail-field-name">Parameters:</th><td class="gmail-field-body"><p class="gmail-first"><strong>initial_paths</strong> (<code class="gmail-xref gmail-py gmail-py-class gmail-docutils gmail-literal gmail-notranslate"><span class="gmail-pre">List</span></code>[<code class="gmail-xref gmail-py gmail-py-class gmail-docutils gmail-literal gmail-notranslate"><span class="gmail-pre">Path</span></code>]) – initial paths as absolute paths</p>
</td>
</tr>
<tr class="gmail-field-even gmail-field"><th class="gmail-field-name">Return type:</th><td class="gmail-field-body"><p class="gmail-first"><code class="gmail-xref gmail-py gmail-py-class gmail-docutils gmail-literal gmail-notranslate"><span class="gmail-pre">List</span></code>[<code class="gmail-xref gmail-py gmail-py-class gmail-docutils gmail-literal gmail-notranslate"><span class="gmail-pre">Path</span></code>]</p>
</td>
</tr>
<tr class="gmail-field-odd gmail-field"><th class="gmail-field-name">Returns:</th><td class="gmail-field-body"><p class="gmail-first">list of initial files (<em>i.e.</em> no directories)</p>
</td>
</tr>
<tr class="gmail-field-even gmail-field"><th class="gmail-field-name">Requires:</th><td class="gmail-field-body"><ul class="gmail-first gmail-simple"><li><code class="gmail-code gmail-docutils gmail-literal gmail-notranslate"><span class="gmail-pre">all(pth.is_absolute()</span> <span class="gmail-pre">for</span> <span class="gmail-pre">pth</span> <span class="gmail-pre">in</span> <span class="gmail-pre">initial_paths)</span></code></li></ul>
</td>
</tr>
<tr class="gmail-field-odd gmail-field"><th class="gmail-field-name">Ensures:</th><td class="gmail-field-body"><ul class="gmail-first gmail-last gmail-simple"><li><code class="gmail-code gmail-docutils gmail-literal gmail-notranslate"><span class="gmail-pre">len(result)</span> <span class="gmail-pre">>=</span> <span class="gmail-pre">len(initial_paths)</span> <span class="gmail-pre">if</span> <span class="gmail-pre">initial_paths</span> <span class="gmail-pre">else</span> <span class="gmail-pre">result</span> <span class="gmail-pre">==</span> <span class="gmail-pre">[]</span></code></li><li><code class="gmail-code gmail-docutils gmail-literal gmail-notranslate"><span class="gmail-pre">all(pth.is_absolute()</span> <span class="gmail-pre">for</span> <span class="gmail-pre">pth</span> <span class="gmail-pre">in</span> <span class="gmail-pre">result)</span></code></li><li><code class="gmail-code gmail-docutils gmail-literal gmail-notranslate"><span class="gmail-pre">all(pth.is_file()</span> <span class="gmail-pre">for</span> <span class="gmail-pre">pth</span> <span class="gmail-pre">in</span> <span class="gmail-pre">result)</span></code></li></ul></td></tr></tbody></table></dd></dl><br></div><div>How is this difficult to read, unless the reader is not familiar with formalism and has a hard time parsing the quantifiers and logic rules? Mind that all these bits are deemed <i>important</i> by the writer -- and need to be included in the function description  <i>somehow</i> -- you can choose between 1)-5). 1) seems obviously best to me. 1) will be tested at least at test time<i>. </i>If I have a bug in the implementation (<i>e.g., </i>I include a directory in the result), the testing framework will notify me again. <br><br></div><div>Here is what the reader would have needed to read without the formalism in the docstring as text (<i>i.e., </i>2):<br></div><div>* All input paths must be absolute.<br></div><div>* If the initial paths are empty, the result is an empty list.<br></div><div>* All the paths in the result are also absolute.<br></div><div>* The resulting paths only include files.<br></div><div><br></div><div>and here is an example with doctest (3):<font size="2"><br></font></div><pre style="background-color:rgb(255,255,255);color:rgb(0,0,0);font-family:"DejaVu Sans Mono""><font size="2">>>> result = packagery.resolve_initial_paths([])<br>[]<br><br>>>> <span style="color:rgb(0,0,128);font-weight:bold">with </span>temppathlib.NamedTemporaryFile() <span style="color:rgb(0,0,128);font-weight:bold">as </span>tmp1, \<br>...         temppathlib.NamedTemporaryFile() <span style="color:rgb(0,0,128);font-weight:bold">as </span>tmp2:<br>...     tmp1.path.write_text(<span style="color:rgb(0,128,128);font-weight:bold">"some text"</span>)<br>...     tmp2.path.write_text(<span style="color:rgb(0,128,128);font-weight:bold">"another text"</span>)<br>...     result = packagery.resolve_initial_paths([tmp1, tmp2])<br>...     <span style="color:rgb(0,0,128);font-weight:bold">assert </span><span style="color:rgb(0,0,128)">all</span>(pth.is_absolute() <span style="color:rgb(0,0,128);font-weight:bold">for </span>pth <span style="color:rgb(0,0,128);font-weight:bold">in </span>result)<br>...     <span style="color:rgb(0,0,128);font-weight:bold">assert </span><span style="color:rgb(0,0,128)">all</span>(pth.is_file() <span style="color:rgb(0,0,128);font-weight:bold">for </span>pth <span style="color:rgb(0,0,128);font-weight:bold">in </span>result)<br><br>>>> <span style="color:rgb(0,0,128);font-weight:bold">with </span>temppathlib.TemporaryDirectory() <span style="color:rgb(0,0,128);font-weight:bold">as </span>tmp:<br>...     packagery.resolve_initial_paths([tmp.path])<br>Traceback (most recent call last):<br>        ...<br><span style="color:rgb(0,0,128)">ValueError</span>(<span style="color:rgb(0,128,128);font-weight:bold">"Unexpected directory in the paths"</span>)</font></pre><div><pre style="background-color:rgb(255,255,255);color:rgb(0,0,0);font-family:"DejaVu Sans Mono""><font size="2">>>> <span style="color:rgb(0,0,128);font-weight:bold">with </span>temppathlib.TemporaryDirectory() <span style="color:rgb(0,0,128);font-weight:bold">as </span>tmp:<br>...     pth = tmp.path / <span style="color:rgb(0,128,128);font-weight:bold">"some-file.py"<br></span>...     pth.write_text(<span style="color:rgb(0,128,128);font-weight:bold">"some text"</span>)<br>...     packagery.initial_paths([pth.relative_to(tmp.path)])<br>Traceback (most recent call last):<br>        ...<br><span style="color:rgb(0,0,128)">ValueError</span>(<span style="color:rgb(0,128,128);font-weight:bold">"Unexpected relative path in the initial paths"</span>)</font></pre><br>Now, how can reading the text (2, code rot) or reading the doctests (3, longer, includes contracts) be easier and more maintainable compared to reading the contracts? I would be really thankful for the explanation -- I feel really stupid as for me this is totally obvious and, evidently, for other people it is not.<br></div><br></div><div>I hope we all agree that the arguments about this example (resolve_initial_paths) selected here are not particular to pypackagery, but that they generalize to most of the functions and methods out there.<br></div><div><br></div><div><b>Writing contracts is difficult.</b><br></div><div dir="ltr">David wrote:<br><blockquote class="gmail_quote" style="margin:0px 0px 0px 0.8ex;border-left:1px solid rgb(204,204,204);padding-left:1ex">To me, as I've said, DbC imposes a very large cost for both writers and readers of code.<br></blockquote><div><br></div><div>The effort of writing contracts include as of now:<br></div><div>* include icontract (or any other design-by-contract library) to setup.py (or requirements.txt), one line one-off<br></div><div>* include sphinx-icontract to docs/source/conf.py and docs/source/requirements.txt, two lines, one-off<br></div><div>* write your contracts (usually one line per contract).<br><br></div><div>The contracts (1) in the above-mentioned function look like this (omitting the contracts run only at test time):<font size="2"><br></font><pre style="background-color:rgb(255,255,255);color:rgb(0,0,0);font-family:"DejaVu Sans Mono";font-size:10.5pt"><font size="2"><span style="color:rgb(0,0,178)">@icontract.pre</span>(<span style="color:rgb(0,0,128);font-weight:bold">lambda </span>initial_paths: <span style="color:rgb(0,0,128)">all</span>(pth.is_absolute() <span style="color:rgb(0,0,128);font-weight:bold">for </span>pth <span style="color:rgb(0,0,128);font-weight:bold">in </span>initial_paths))<br><span style="color:rgb(0,0,178)">@icontract.post</span>(<span style="color:rgb(0,0,128);font-weight:bold">lambda </span>result: <span style="color:rgb(0,0,128)">all</span>(pth.is_file() <span style="color:rgb(0,0,128);font-weight:bold">for </span>pth <span style="color:rgb(0,0,128);font-weight:bold">in </span>result))<br><span style="color:rgb(0,0,178)">@icontract.post</span>(<span style="color:rgb(0,0,128);font-weight:bold">lambda </span>result: <span style="color:rgb(0,0,128)">all</span>(pth.is_absolute() <span style="color:rgb(0,0,128);font-weight:bold">for </span>pth <span style="color:rgb(0,0,128);font-weight:bold">in </span>result))<br><span style="color:rgb(0,0,178)">@icontract.post</span>(<span style="color:rgb(0,0,128);font-weight:bold">lambda </span>initial_paths, result: <span style="color:rgb(0,0,128)">len</span>(result) >= <span style="color:rgb(0,0,128)">len</span>(initial_paths) <span style="color:rgb(0,0,128);font-weight:bold">if </span>initial_paths <span style="color:rgb(0,0,128);font-weight:bold">else </span>result == [])<br><span style="color:rgb(0,0,128);font-weight:bold">def </span>resolve_initial_paths(initial_paths: List[pathlib.Path]) -> List[pathlib.Path]:<br>    ...<br></font></pre></div><div>Putting aside how this code could be made more succinct (use "args" or "a" argument in the condition to represent the arguments, using from ... import ..., renaming "result" argument to "r", introducing a shortcut methods slowpre and slowpost to encapsulate the slow contracts not to be executed in the production), how is this difficult to write? It's 4 lines of code.<br><br></div><div>Writing text (2) is 4 lines. Writing doctests (3) is 23 lines and includes the contracts. Again, given that the writer is trained in writing formal expressions, the mental effort is the same for writing the text and writing the formal contract (in cases of non-native English speakers, I'd even argue that formal expressions are sometimes <i>easier</i> to write).<br><br></div><div><b>99% vs 1%</b><br><blockquote class="gmail_quote" style="margin:0px 0px 0px 0.8ex;border-left:1px solid rgb(204,204,204);padding-left:1ex">I'm not alone in this. A large majority of folks formally educated in 
computer science and related fields have been aware of DbC for decades 
but deliberately decided not to use them in their own code. Maybe you 
and Bertram Meyer are simple better than that 99% of programmers... Or 
maybe the benefit is not so self-evidently and compelling as it feels to
 you.</blockquote></div><div><br>I think that ignorance plays a major role here. Many people have misconceptions about the design-by-contract. They just use 2) for more complex methods, or 3) for rather trivial methods. They are not aware that it's easy to use the contracts (1) and fear using them for non-rational reasons (<i>e.g., </i>habits).<br><br>This is also what Todd Plesel writes in <a href="https://www.win.tue.nl/~wstomv/edu/2ip30/references/design-by-contract/index.html#IfDesignByContractIsSoGreat">https://www.win.tue.nl/~wstomv/edu/2ip30/references/design-by-contract/index.html#IfDesignByContractIsSoGreat</a>:<br><blockquote>The vast majority of those developing software - even that intended to 
be reused - are simply ignorant of the concept. As a result they 
produce application programmer interfaces (APIs) that are 
under-specified thus passing the burden to the application programmer 
to discover by trial and error, the 'acceptable boundaries' of the 
software interface (undocumented contract's terms). But such ad-hoc 
operational definitions of software interface discovered through 
reverse-engineering are subject to change upon the next release and so 
offers no stable way to ensure software correctness.
<p>
The fact that many people involved in writing software lack pertinent 
education (e.g., CS/CE degrees) and training (professional courses, 
read software engineering journals, attend conferences etc.) is <i>not</i>
 a reason they don't know about DBC since the concept is not covered 
adequately in such mediums anyway. That is, <i>ignorance of DBC extends 
not just throughout practitioners but also throughout educators and 
many industry-experts.</i></p></blockquote></div><div>He lists some more factors and misconceptions that hinder the adoption. I would definitely recommend you to read at least that section if not the whole piece. <br><br>The conclusion paragraph "Culture Shift: Too Soon or Too Late" was also telling:<br><blockquote class="gmail_quote" style="margin:0px 0px 0px 0.8ex;border-left:1px solid rgb(204,204,204);padding-left:1ex"><b>The simplicity and obvious benefits of Design By Contract lead one to 
wonder why it has not become 'standard practice' in the software 
development industry.</b> When the concept has been explained to various 
technical people (all non-programmers), they invariably agree that it 
is a sensible approach and some even express dismay that software 
components are not developed this way.
<p>
It is just another indicator of the immaturity of the software 
development industry. The failure to produce high-quality products is 
also blatantly obvious from the non-warranty license agreement of 
commercial software. Yet consumers continue to buy software they 
suspect and even expect to be of poor quality. Both quality and 
lack-of-quality have a price tag, but the difference is in who pays and 
when. As long as companies can continue to experience rising profits 
while selling poor-quality products, what incentive is there to change? 
Perhaps the fall-out of the "Year 2000" problem will focus 
enough external pressure on the industry to jolt it towards improved 
software development methods. There is talk of certifying programmers 
like other professionals. If and when that occurs, the benefits of 
Design By Contract just might begin to be appreciated.</p>
<p>
But it is doubtful. Considering the typical 20 year rule for adopting 
superior technology, DBC as exemplified by Eiffel, has another decade 
to go. But if Java succeeds in becoming a widely-used language and 
JavaBeans become a widespread form of reuse then it would already be 
too late for DBC to have an impact. iContract will be a hardly-noticed 
event much like ANNA for Ada and A++ for C++. This is because <i>the 
philosophy/mindset/culture is established by the initial publication of 
the language and its standard library.</i></p></blockquote>(Emphasis mine; iContract refers to a Java design-by-contract library)<br></div><div><br>Hence the salient argument is the lack of <i>tools</i> for DbC. So far, none of the existing DbC libraries in Python really have the capabilities to be included in the code base. The programmer had to duplicate the contract, the messages did not include the values involved in the condition, one could not inherit the contracts and the contracts were not included in the documentation. Some libraries supported some of these features, but none up to icontract library supported them all. icontract finally supports all these features. <br><br>I have <i>never</i> seen a rational argument how writing contracts (1) is <i>inferior </i>to approaches 2-5), except that it's hard for programmers untrained in writing formal expressions and for the lack of tools. I would be really thankful if you could address these points and show me where I am wrong <i>given that formalism and tools are not a problem</i>. We can train the untrained, and we can develop tools (and put them into standard library). This will push adoption to far above 1%. <br><br></div><div>Finally, it is <i>obvious</i> to me that the documentation is important. I see lacking documentation as one of the major hits in the productivity of a programmer. If there is a tool that could easily improve the documentation (<i>i.e. </i>formal contracts with one line of code per contract) and automatically keep it in sync with the code (by checking the contracts during the testing), I don't see any <i>rational </i>reason why you would dispense of such a tool. Again, please do correct me and contradict -- I don't want to sound condescending or arrogant -- I literally can't wrap my head around why <i>anybody</i> would dispense of a such an easy-to-use tool that gives you better documentation (<i>i.e. </i>superior to approaches 2-5) except for lack of formal skills and lack of supporting library. If you think that the documentation is <i>not </i>important, then please, do explain that since it goes counter to all my previous experience and intuition (which, of course, can be wrong).<br></div><div><br></div></div><div><b>Why not Eiffel?</b> <br></div><div>Hugh wrote:<br></div><div dir="ltr"><blockquote class="gmail_quote" style="margin:0px 0px 0px 0.8ex;border-left:1px solid rgb(204,204,204);padding-left:1ex">Secondly, these "obvious" benefits. If they're obvious, I want to know why<br>
aren't you using Eiffel? It's a programming language designed around DbC<br>
concepts. It's been around for three decades, at least as long as Python or<br>
longer. There's an existing base of compilers and support tools and libraries<br>
and textbooks and experienced programmers to work with.<br>
<br>
Could it be that Python has better libraries, is faster to develop for, attracts<br>
more programmers? If so, I suggest it's worth considering that this might<br>
be *because* Python doesn't have DbC.</blockquote><div><br></div><div>Python is easier to write and read, and there are no libraries which are close in quality in Eiffel space (notably, Numpy, OpenCV, nltk and sklearn). I really don't see how the quality of these libraries have anything to do with lack (or presence) of the contracts. OpenCV and Numpy have contracts all over their code (written as assertions and not documented), albeit with very non-informative violation messages. And they are great libraries. Their users would hugely benefit from a more mature and standardized contracts library with informative violation messages.<br><br></div><div><b>Duck Typing<br></b></div><div>Hugh wrote:<br></div><div><blockquote class="gmail_quote" style="margin:0px 0px 0px 0.8ex;border-left:1px solid rgb(204,204,204);padding-left:1ex">And I wouldn't use DbC for Python because<br>
I wouldn't find it helpful for the kind of dynamic, exploratory development<br>
I do in Python. I don't write strict contracts for Python code because in a<br>
dynamically typed, and duck typed, programming language they just don't<br>
make sense to me. Which is not to say I think Design by Contract is bad,<br>
just that it isn't good for Python.<br></blockquote><div><br></div><div>I really don't see how DbC has<i> </i>to do with duck typing (unless you reduce it to mere isinstance conditions, which would simply be a straw-man argument) -- could you please clarify? As soon as you need to document your code, and this is what most modules have to do in teams of more than one person (especially so if you are developing a library for a wider audience), you need to write down the contracts. Please see above where I tried to explained  that 2-5) are inferior approaches to documenting contracts compared to 1).<br><br></div><div>As I wrote above, I would be very, very thankful if you point me to other approaches (apart from 1-5) that are superior to contracts or state an argument why approaches 2-5) are superior to the contracts since that is what I<i> </i>miss to see.<br></div><div><br></div><div>Cheers,<br></div><div>Marko<br></div><div><br></div></div></div></div></div></div></div></div></div></div></div></div></div></div></div></div></div></div></div></div></div></div></div></div></div><br><div class="gmail_quote"><div dir="ltr">On Sun, 23 Sep 2018 at 12:34, Hugh Fisher <<a href="mailto:hugo.fisher@gmail.com" target="_blank">hugo.fisher@gmail.com</a>> wrote:<br></div><blockquote class="gmail_quote" style="margin:0 0 0 .8ex;border-left:1px #ccc solid;padding-left:1ex">> Date: Sun, 23 Sep 2018 07:09:37 +0200<br>
> From: Marko Ristin-Kaufmann <<a href="mailto:marko.ristin@gmail.com" target="_blank">marko.ristin@gmail.com</a>><br>
> To: Python-Ideas <<a href="mailto:python-ideas@python.org" target="_blank">python-ideas@python.org</a>><br>
> Subject: [Python-ideas] Why is design-by-contracts not widely adopted?<br>
<br>
[ munch ]<br>
<br>
> *. *After properly reading about design-by-contract and getting deeper into<br>
> the topic, there is no rational argument against it and the benefits are<br>
> obvious. And still, people just wave their hand and continue without<br>
> formalizing the contracts in the code and keep on writing them in the<br>
> descriptions.<br>
<br>
Firstly, I see a difference between rational arguments against Design By<br>
Contract (DbC) and against DbC in Python. Rejecting DbC for Python is<br>
not the same as rejecting DbC entirely.<br>
<br>
Programming languages are different, obviously. Python is not the same<br>
as C is not the same as Lisp... To me this also means that different<br>
languages are used for different problem domains, and in different styles<br>
of development. I wouldn't use DbC in programming C or assembler<br>
because it's not really helpful for the kind of low level close to the machine<br>
stuff I use C or assembler for. And I wouldn't use DbC for Python because<br>
I wouldn't find it helpful for the kind of dynamic, exploratory development<br>
I do in Python. I don't write strict contracts for Python code because in a<br>
dynamically typed, and duck typed, programming language they just don't<br>
make sense to me. Which is not to say I think Design by Contract is bad,<br>
just that it isn't good for Python.<br>
<br>
Secondly, these "obvious" benefits. If they're obvious, I want to know why<br>
aren't you using Eiffel? It's a programming language designed around DbC<br>
concepts. It's been around for three decades, at least as long as Python or<br>
longer. There's an existing base of compilers and support tools and libraries<br>
and textbooks and experienced programmers to work with.<br>
<br>
Could it be that Python has better libraries, is faster to develop for, attracts<br>
more programmers? If so, I suggest it's worth considering that this might<br>
be *because* Python doesn't have DbC.<br>
<br>
Or is this an updated version of the old saying "real programmers write<br>
FORTRAN in any language" ? If you are accustomed to Design by Contract,<br>
think of your time in the Python world as a trip to another country. Relax<br>
and try to program like the locals do. You might enjoy it.<br>
<br>
-- <br>
<br>
        cheers,<br>
        Hugh Fisher<br>
_______________________________________________<br>
Python-ideas mailing list<br>
<a href="mailto:Python-ideas@python.org" target="_blank">Python-ideas@python.org</a><br>
<a href="https://mail.python.org/mailman/listinfo/python-ideas" rel="noreferrer" target="_blank">https://mail.python.org/mailman/listinfo/python-ideas</a><br>
Code of Conduct: <a href="http://python.org/psf/codeofconduct/" rel="noreferrer" target="_blank">http://python.org/psf/codeofconduct/</a><br>
</blockquote></div>