<div dir="ltr"><div><div><div><div><div><div><div><div><div><div><div><div><div><div><div><div><div><div>Hello everyone!<br><br></div>Recently I've been looking for a best way to fix incorrect handling of defaults in MuranoPL's property contracts [1]. I analyzed how contracts used in applications that are currently in app-incubator, typical mistakes and usage patterns. I've found number of places where contract system can be significantly improved. Here is my list of proposed improvements I'd like to deliberate with you:<br>




<br></div>Problem: when contract violation happens it is very hard to tell without debugger what went wrong. Especially this is a problem for complex nested structures. Currently it even impossible to tell which property caused exception during class load<br>




<br></div>Solution: during contract traversal keep track of path to a part of contract being processed (for example 'foo/0/bar'). Include that path in every thrown exception alongside with human-readable description describing what value was processed and what contract was violated. Prepend property name to exception text so that is would be clear what property cannot be initialized. The same for method arguments.<br>



<br>---<br><br></div>Problem: Single default value is not enough for properties that are not of scalar type.<br></div>For example if we have contract like<br></div></div>- name: $.string()<br></div>  disabled: $.bool()<br>


<br></div>
(array of structures) it is reasonable to have default value for "disabled" attribute of each list entry whereas there is no meaningful default for "name" attribute. Current approach allows to provide initial filling of entire array which is obviously not what developer expects.<br>


<br></div>Solution: to have Default reflect contract structure so that different parts of Default can serve as an independent defaults for corresponding parts of the contract. Default need to be traversed in parallel with contract spec and provided value. Default value need not provide value for every single attribute mentioned in contract spec and thus can be simpler than contract itself.<br>


<br>---<br><br></div>Problem: Default value is only used when no property value provided at all. Null (None) value is a valid value even if it not valid for particular contract. Thus is null is passed Default is not used.<br>


<br></div>Solution: to treat every missing value as null. Missing Default is also considered to be null. This greatly simplifies understanding of contracts and client development (it is easier to set attribute value to None rather then deleting attribute from object if default value is desired, especially for generic clients)<br>


<br>---<br><br></div>Problem: most of the time developer writes $.int() contract he doesn't realize that null is also valid value for such contract and the correct form is $.int().notNull(). This is even more obvious in case of bool(). Developers are lazy and usually forget to wright long verbose contracts.<br>


</div><br>Solution: to make all primitive types be not-nullable with obvious defaults (0 for int, false for bool).<br></div>This is enough for 95% of use cases. For the rest 5% where null value does valid to have separate contract methods optionalInt(), optionalBool() etc.<br>


<br></div>As for strings I think that the same approach should be used - $.string() is a non-nullable sequence of chars with empty string as a default. And there should also be optionalString() that es equal to current $.string(). But in most cases when developer writes $.string() what he really wants is $.string().notNull().trim().notEmpty(). So while it is reasonable to have all this helper functions (notEmpty(), notBlank(), trim() etc.) is would be great to have one contract function that does exactly that.<br>


<br></div>---<br><br>While some of proposed changes can possible break existing contracts in practice they just legalize current state of affairs so nothing would break.<br><br></div>What do you think?<br>
<div><div><div><div><div><div><div><div><div><div><div><div><br><div><div><div><div><div><div><div><div><div><div><div><div><div><div>[1]: <a href="https://bugs.launchpad.net/murano/+bug/1313694" target="_blank">https://bugs.launchpad.net/murano/+bug/1313694</a><br>

<br clear="all"><div><div dir="ltr">

<span style="border-collapse:separate;color:rgb(0,0,0);font-family:'Times New Roman';font-style:normal;font-variant:normal;font-weight:normal;letter-spacing:normal;line-height:normal;text-indent:0px;text-transform:none;white-space:normal;word-spacing:0px;font-size:medium"><span style="font-family:arial;font-size:small">Sincerely yours,<br>




Stan Lagun<br>Principal Software Engineer @ Mirantis</span></span><br><span style="border-collapse:separate;color:rgb(0,0,0);font-family:'Times New Roman';font-style:normal;font-variant:normal;font-weight:normal;letter-spacing:normal;line-height:normal;text-indent:0px;text-transform:none;white-space:normal;word-spacing:0px;font-size:medium"><span style="font-family:arial;font-size:small"><br>




<a href="mailto:slagun@mirantis.com" target="_blank"></a></span></span></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></div></div></div></div>