<div dir="ltr"><div dir="ltr"><div dir="ltr"><div dir="ltr"><div dir="ltr"><div dir="ltr"><div dir="ltr"><div><div>Hi Chris and Paul,<br><br></div>Let me please answer your messages in one go as they are related.<br><br></div>Paul wrote:<br><blockquote class="gmail_quote" style="margin:0px 0px 0px 0.8ex;border-left:1px solid rgb(204,204,204);padding-left:1ex">For most single use (or infrequently used) functions, I'd argue that the trade-off *isn't* worth it.<br>
<br>
Here's a quick example from the pip codebase:<br>
<br>
# Retry every half second for up to 3 seconds<br>
@retry(stop_max_delay=3000, wait_fixed=500)<br>
def rmtree(dir, ignore_errors=False):<br>
shutil.rmtree(dir, ignore_errors=ignore_errors,<br>
onerror=rmtree_errorhandler)</blockquote><div><br></div><div>Absolutely, I agree. If it's a single-use or infrequently used function that hardly anybody uses, it's not worth it. Moreover, if some contracts are harder to figure out than the implementation, then they are probably in most cases not worth the effort, too. <br><br></div><div>Please mind that I said: any <i>library</i> would benefit from it, as in the users of any library on pipy would benefit from better, formal and more precise documentation. That doesn't imply that all the contracts need to be specified or that you have to specify the contract for <i>every </i>function, or that you omit the documentation altogether. Some contracts are simply too hard to get explicitly. Some are not meaningful even if you could write them down. Some you'd like to add, but run only at test time since too slow in production. Some run in production, but are not included in the documentation (<i>e.g., </i>to prevent the system to enter a bad state though it is not meaningful for the user to actually <i>read</i> that contract).<br><br></div><div>Since contracts are formally written, they can be verified. Human text <i>can not</i>. Specifying all the contracts is in most cases <i>not </i>meaningful. In my day-to-day programming, I specify contracts on the fly and they help me express formally to the next girl/guy who will use my code what to expect or what not. That does not mean that s/he can just skip the documentation or that contracts describe fully what the function does. They merely help -- help him/her what arguments and results are expected. That <i>does not mean </i>that I fully specified all the predicates on the arguments and the result. It's merely a help à la <br>* "Ah, this argument needs to be bigger than that argument!" <br>* "Ah, the resulting dictionary is shorter than the input list!" <br>* "Ah, the result does not include the input list"<br>* "Ah, this function accepts only files (no directories) and relative paths!"<br>* "Ah, I put the bounding box outside of the image -- something went wrong!"<br>* "Ah, this method allows me to put the bounding box outside of the image and will fill all the outside pixels with black!" <i>etc.<br><br></i></div><div>For example, if I have an object detector operating on a region-of-interest and returning bounding boxes of the objects, the postconditions will not be: "all the bounding boxes are cars", that would impossible. But the postcondition might check that all the bounding boxes are within the region-of-interest or slightly outside, but not completely outside <i>etc.</i><br></div><div><i><br></i></div><div>Let's be careful not to make a straw-man here, <i>i.e. </i>to push DbC <i>ad absurdum </i>and then discard it that way.<br><br><blockquote class="gmail_quote" style="margin:0px 0px 0px 0.8ex;border-left:1px solid rgb(204,204,204);padding-left:1ex">Also, the implicit contracts code currently has are typically pretty loose. What you need to "figure out" is very general. Explicit contracts are typically demonstrated as being relatively strict, and figuring out and writing such contracts is more work than writing code with loose implicit contracts. Whether the trade-off of defining tight explicit contracts once vs inferring a loose implicit contract every time you call the function is worth it, depends on how often the function is called. For most single use (or infrequently used)
functions, I'd argue that the trade-off *isn't* worth it.</blockquote><div><br></div><div>I don't believe such an approach would ever be pragmatical, <i>i.e. </i>automatic versioning based on the contracts. It might hint it (as a warning: you changed a contract, but did not bump the version), but relying solely on this mechanism to get the versioning would imply that you specified <i>all </i>the contracts. Though Bertrand might have always envisioned it as the best state of the world, even he himself repeatedly said that it's better to specify rather 10% than 0% contracts and 20% rather than 10% contracts. <br></div></div><div><br></div><div>Chris 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">def fibber(n):<br>
return n if n < 2 else fibber(n-1) + fibber(n-2)</blockquote><div> <br></div><div>It depends who you are writing this function for -- for example, instead of the contract, why not just include the code implementation as the documentation? The only <i>meaningful</i> contract I could imagine:<br></div><div>@pre n >= 0<br></div><div><br></div><div>Everything else would be just repetition of the function. If you implemented some optimized and complex fibber_optimized() function, then your contracts would probably look like:<br></div><div>@pre n >= 0<br></div><div>@post (n < 2 ) or result == fibber_optimized(n-1) + fibber_optimized(n-2)<br></div><div>@post not (n < 2) or result == n<br></div><div><br><blockquote class="gmail_quote" style="margin:0px 0px 0px 0.8ex;border-left:1px solid rgb(204,204,204);padding-left:1ex"><span class="gmail-im">> Here is my try at the contracts. Assuming that
there is a list of figures and that they have a property "displayed" and
that "State.blocked" global variable refers to whether the interface is
blocked or not::</span><br><span class="gmail-im">
> @post(lambda: all(figure.displayed for figure in figures)</span><br><span class="gmail-im">
> @post(lambda: not ipython.in_pylab_mode() or not State.blocked)</span><br><span class="gmail-im">
> @post(lambda: not interactive() or State.blocked)</span><br><span class="gmail-im">
> matplotlib.pyplot.show()</span><br><span class="gmail-im">
></span><br><span class="gmail-im">
</span><br><span class="gmail-im"></span>
There is no such thing as "State.blocked". It blocks. The function<br>
*does not return* until the figure has been displayed, and dismissed.<br>
There's no way to recognize that inside the function's state.<br>
<br>
Contracts are great when every function is 100% deterministic and can<br>
maintain invariants and/or transform from one set of invariants to<br>
another. Contracts are far less clear when the definitions are<br>
muddier.<br></blockquote></div><br></div><div>Sorry, it has been ages that I used matplotlib. I thought it meant "blocking" as in "the drawing thread blocks". Since blocking basically means halting the execution-- then the contracts can't help. They are checked <i>before </i>and <i>after </i>the function executes. They can not solve the halting problem. For that you need formal methods (and I doubt that formal methods would ever work for matplotlib). The contracts <i>do not check </i>what happens <i>during </i>the execution of the function. They are not meant to do that. Even the invariants of the class are checked <i>before </i>and <i>after the call to public methods </i>(and the private methods are allowed to break them!).<br><br></div><div>Please mind that this is actually not the argument pro/against the contracts -- you are discussing in this particular case a tool (different to DbC) which should test the behavior <i>during the execution </i>of a function.<br></div><div><br></div><div>Chirs 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"><span class="gmail-im">> However, contracts can be useful when testing the
GUI -- often it is difficult to script the user behavior. What many
people do is record a session and re-play it. If there is a bug, fix it.
Then re-record. While writing unit tests for GUI is hard since GUI
changes rapidly during development and scripting formally the user
behavior is tedious, DbC might be an alternative where you specify as
much as you can, and then just re-run through the session. This implies,
of course, a human tester.</span><br><span class="gmail-im">
></span><br><span class="gmail-im">
</span><br><span class="gmail-im"></span>
That doesn't sound like the function's contract. That sounds like a<br>
test case - of which you would have multiple, using different<br>
"scripted session" inputs and different outputs (some of success, some<br>
of expected failure).<span class="gmail-im"></span><br><span class="gmail-im"></span></blockquote><br></div><div>Well, yes, you can view it as a testing technique; it assumes that scripting a session is often difficult for GUIs and sometimes harder (since combinatorial) than the implementation itself. What I saw people do is write the contracts, put the program in debug mode and let the human tester test it. Think of it as a random test where only checks are your pre/postconditions. The human annotator mimics a meaningful random walk and uses the application as s/he sees fit. I'm not championing this approach, just noting it here as a potential use case.<br></div><div><br><blockquote class="gmail_quote" style="margin:0px 0px 0px 0.8ex;border-left:1px solid rgb(204,204,204);padding-left:1ex">There's certainly benefits for the "contracts as additional tests"<br>
viewpoint. But whenever that's proposed as what people understand by<br>
DbC, the response is "no, it's not like that at all". So going back to<br>
the "why isn't DbC more popular" question - because no-one can get a<br>
clear handle on whether they are "like tests" or "like assertions" or<br>
"something else" :-)</blockquote><div> <br></div></div><div>I think that it's a tool that you can use for many things: <br></div><div>* verifiable documentation<br></div><div>* deeper testing (every test case tests also other parts of the system, akin to asserts)<br></div><div>* automatic test generation<br></div><div>* hand-break akin to asserts<br></div><div><br></div><div>I find the first one, verifiable documentation, to be the most useful one in working with my team at the moment.<br></div><div><br></div><div>Cheers,<br></div><div>Marko <br></div></div></div></div></div></div></div></div><br><div class="gmail_quote"><div dir="ltr">On Wed, 26 Sep 2018 at 10:59, Paul Moore <<a href="mailto:p.f.moore@gmail.com">p.f.moore@gmail.com</a>> wrote:<br></div><blockquote class="gmail_quote" style="margin:0 0 0 .8ex;border-left:1px #ccc solid;padding-left:1ex">On Wed, 26 Sep 2018 at 09:45, Chris Angelico <<a href="mailto:rosuav@gmail.com" target="_blank">rosuav@gmail.com</a>> wrote:<br>
><br>
> On Wed, Sep 26, 2018 at 6:36 PM Paul Moore <<a href="mailto:p.f.moore@gmail.com" target="_blank">p.f.moore@gmail.com</a>> wrote:<br>
> ><br>
> > On Wed, 26 Sep 2018 at 06:41, Chris Angelico <<a href="mailto:rosuav@gmail.com" target="_blank">rosuav@gmail.com</a>> wrote:<br>
> > ><br>
> > > On Wed, Sep 26, 2018 at 2:47 PM Marko Ristin-Kaufmann<br>
> > > <<a href="mailto:marko.ristin@gmail.com" target="_blank">marko.ristin@gmail.com</a>> wrote:<br>
> > > > * The contracts written in documentation as human text inevitably rot and they are much harder to maintain than automatically verified formal contracts.<br>
> > ><br>
> > > Agreed.<br>
> ><br>
> > Agreed, if contracts are automatically verified. But when runtime cost<br>
> > comes up, people suggest that contracts can be disabled in production<br>
> > code - which invalidates the "automatically verified" premise.<br>
><br>
> Even if they're only verified as a dedicated testing pass ("okay,<br>
> let's run the unit tests, let's run the contract verifier, let's run<br>
> the type checker, cool, we're good"), they're still better off than<br>
> unchecked comments/documentation in terms of code rot.<br>
<br>
Absolutely. But if the contracts are checked at runtime, they are<br>
precisely as good as tests - they will flag violations *in any<br>
circumstances you check*. That's great, but nothing new. I understood<br>
that one of the benefits of contracts was that it would handle cases<br>
that you *forgot* to test - like assertions do, in essence - and would<br>
need to be active in production (again, like assertions, if we assume<br>
we've not explicitly chosen to run with assertions disabled) to get<br>
that benefit.<br>
<br>
There's certainly benefits for the "contracts as additional tests"<br>
viewpoint. But whenever that's proposed as what people understand by<br>
DbC, the response is "no, it's not like that at all". So going back to<br>
the "why isn't DbC more popular" question - because no-one can get a<br>
clear handle on whether they are "like tests" or "like assertions" or<br>
"something else" :-)<br>
<br>
Paul<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>