<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 Chris,<br><br><blockquote class="gmail_quote" style="margin:0px 0px 0px 0.8ex;border-left:1px solid rgb(204,204,204);padding-left:1ex">If not, all your proposed benefits can be achieved at the level of a<br>
single project, by just saying "we're going to use THIS contracts<br>
library", unless I'm misunderstanding something here.<br></blockquote>
<br>
<br></div><div>I think we are having a big disconnect in the discussion. Please apologize for my vagueness and point me where you would like me to elaborate more. Let me try to have another iteration where I'll try to paraphrase myself and illustrate what I think that you are thinking.<br><br></div><div>I imagine that you conceive contracts purely as an approach to a testing to be applied to a single project. I'm not talking about that. I'm talking about two packages on pypi, both specifying contracts, each developed by a separate team from different organizations. Let's call these packages package_a and package_b, respectively (and team A and B, analogously).<br><br></div><div>Imagine now that the contracts are not standardized. For example, team A uses dpcontracts whereas team B uses icontract. Enter team C working on the package_c. <br><br>There is a class package_c.SomeClass that needs to inherit both from package_a.some_module.BaseClass and from package_b.another_module.AnotherBaseClass. Imagine the mess that developers in team C have to deal with -- how are contracts supposed to be strengthened and weakened in package_c.SomeClass? A nightmare with different contract libraries. Even if they don't have to work with multiple inheritance, they would need to use different syntaxes for different concrete classes inheriting from the two packages, respectively. And now think of contract groups that can be specified and applied to 
functions:<br><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)">@require</span>(...)<br><span style="color:rgb(0,0,178)">@require</span>(...)<br><span style="color:rgb(0,0,178)">@ensure</span>(...)<br><span style="color:rgb(0,0,128);font-weight:bold">def </span>some_func(...):<br>    ...<br><br><span style="color:rgb(0,0,178)">@enforce_contracts_of</span>(some_func)</font><br><font size="2"><font size="2"><span style="color:rgb(0,0,178)">@require</span>(...)<br></font><span style="color:rgb(0,0,128);font-weight:bold">def </span>some_other_func(...):<br>    ...<br><br></font></pre><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">some_group = [<br>    require(...),<br>    ensure(...),<br>    ensure(...)<br>]<br><br><span style="color:rgb(0,0,178)">@enforce_contracts</span>(some_group)</font><br><font size="2"><font size="2"><span style="color:rgb(0,0,178)">@ensure</span>(...)</font><br><span style="color:rgb(0,0,128);font-weight:bold">def </span>yet_another_function(...):<br>    ...</font><br></pre><br>How are these contract groups supposed to play together between package_a and package_b when applied in package_c? (A side remark: the name and implementation of "enforce_contracts_of" and "enforce_contracts" are still in discussion for icontract and have not been implemented yet.)<br><br>Furthermore, what about toggling contracts? Team C needs to know both how to toggle the contracts of package_a.some_module and also how to toggle the contracts of package_b.another_module. They need to be aware of and probably set two different environment variables with different toggling granularities <i>etc</i>. What if the toggling conflicts? <br><br></div><div>Even if they both used, say, icontract. Package_a might require icontract 1.x whereas package_b requires 2.x. This results in a dependency hell. A standardized lib would force both packages to use the same version of contract lib (or not be supported in that given python version at all) -- the compatibility would be dictated by the python version, not by the version of a non-standard contract lib. <br><br></div><div>Let's focus now on the team working on mypy. For example, consider the code:<br><pre style="background-color:rgb(255,255,255);color:rgb(0,0,0);font-family:"DejaVu Sans Mono";font-size:10.5pt"><span style="color:rgb(0,0,178)">@invariant</span>(<span style="color:rgb(0,0,128);font-weight:bold">lambda </span>self: self.something <span style="color:rgb(0,0,128);font-weight:bold">is not None or </span>self.another <span style="color:rgb(0,0,128);font-weight:bold">is not None</span>)<br><span style="color:rgb(0,0,128);font-weight:bold">class </span>SomeClass:<br>    ...<br><br><span style="color:rgb(128,128,128);font-style:italic"># later in code somewhere<br></span><span style="color:rgb(0,0,128);font-weight:bold">def </span>some_func():<br>    s = SomeClass(...)<br>    <span style="color:rgb(0,0,128);font-weight:bold">if </span>s.something <span style="color:rgb(0,0,128);font-weight:bold">is None</span>:<br>        <span style="color:rgb(128,128,128);font-style:italic"># </span><span style="color:rgb(128,128,128);font-style:italic">mypy knows here that s.another is not None.<br></span><span style="color:rgb(128,128,128);font-style:italic">        </span>...</pre></div><div>But if there existed multiple non-standard contract libraries, can we really expect that mypy deals with all of them? I couldn't possibly imagine that.<br><br></div><div>If these points are still not clear -- imagine having multiple non-standard, but widely used libraries and approaches for abstract base classes or object-oriented programming. A horrifying thought :) I'd probably even prefer the python world without contracts than with a widespread use of multiple contract libraries.<br></div><div><br></div><div>If pythonistas are to use contracts more widely without stomping on each other's feet, there needs to be some form of standardization so that different packages can inter-operate. There needs to be a convention how to toggle the contracts at different levels of granularity (individual contracts, module-level, pypi package-level, only in testing <i>etc.</i>). Environment variables? Setting global variables before importing a module? Some mechanism I'm not aware of? Are the contracts on or off by default? <br><br>There are so many other details that needs to be fleshed out and this needs to be a collective effort if it is to succeed. I don't have the knowledge to figure out all the conceptual details alone and need help from more experienced people.<br><br>---<br><br></div><div>Now a completely different point. Whether we write contracts <i>for</i> the modules of the standard library is another discussion. It is not directly connected with the standardization of contracts (and also not part of the current thread, IMO). To write contracts or not to write contracts for a standard library is a per-module decision and concerns the authors and users of each module in separation. Some modules might include contracts that are run only in test mode (<i>e.g., </i>in case of icontract, that would be the situation when the environment variable ICONTRACT_SLOW is set); other modules might verify only some of them in production; yet other modules might always verify all the contracts. Or standard lib might take the approach that each module has a corresponding environment variable to turn <i>on </i>the contracts, while its contracts are disabled by default.<br><br>In current implementation of icontract, there is a negligible overhead at the moment during the import of a module with disabled contracts (numbers from the previous message; average over 10 runs, in milliseconds):<br>Duration to import the module functions_100_with_no_contract : 795.59 ± 10.47<br><br>Duration to import the module functions_100_with_1_disabled_contract : 833.60 ± 32.07<br>Duration to import the module functions_100_with_5_disabled_contracts : 851.31 ± 66.93<br>Duration to import the module functions_100_with_10_disabled_contracts : 897.90 ± 143.02</div><div><br></div><div>The whole import overhead is attributed to the interpreter having to parse the decorators and the call to the decorator at the import time (when the decorator immediately returns the wrapped function). If this overhead is unacceptable -- then we need to figure out how to circumvent the parsing of contracts in the interpreter directly and ignore the contract decorators which are disabled. Or have a code base which is shipped for production and another one which is shipped for testing (the former would have the contracts automatically stripped out). This overhead is a limitation of <i>any </i>decorator -- <i>e.g.,</i> if abstract base classes are OK, I don't see why contracts wouldn't be.<br></div><div><br></div><div>I could think of many other optimizations in CPython (<i>e.g., </i>it could in-line the code to verify the condition in the function body to avoid making two calls, one to the wrapper and another to the wrapped function), but this is really not the topic of the current thread (please feel free to fork to another thread if you'd like to discuss that particular topic).<br></div><div><br>---<br><br></div><div>My conclusion is at this point is that the best course of action would be that other teams pick up a contract library (now that there is at least icontract library with a full feature set for design-by-contract akin to Eiffel and other languages), and present us how they use contracts and what problems they were facing (<i>e.g., </i>were there any problems with the toggling granularity? readability? maintainability?). Then we decide how to proceed.</div><div><br></div><div>What are the opinions of the other folks that would like to have a standardized contract library?<br></div><div><br></div><div>Cheers,<br></div><div>Marko<br></div></div></div></div></div></div></div></div></div></div></div>