On Fri, 28 Sep 2018 at 13:23, David Mertz
I agree that all the Sphinx documentation examples shown are very nice. Prose descriptions would often be nicer still, but the Boolean expressions are helpful for those unusual cases where I don't want to look at the code.
I'm ambivalent about the Sphinx examples. I find the highly detailed code needed to express a condition fairly unreadable (and I'm an experienced Python programmer). For example @pre(lambda args, result: not any(Path(arg).is_absolute() for arg in args) or (result == [pth for arg in args for pth in [Path(arg)] if pth.is_absolute()][-1]), "When several absolute paths are given, the last is taken as an anchor (mimicking os.path.join()’s behaviour)") The only way I'd read that is by looking at the summary text - I'd never get the sense of what was going on from the code alone. There's clearly a number of trade-offs going on here: * Conditions should be short, to avoid clutter * Writing helper functions that are *only* used in conditions is more code to test or get wrong * Sometimes it's just plain hard to express a verbal constraint in code * Marko isn't that familiar with the codebase, so there may be better ways to express certain things But given that *all* the examples I've seen of contracts have this issue (difficult to read expressions) I suspect the problem is inherent. Another thing that I haven't yet seen clearly explained. How do these contracts get *run*? Are they checked on every call to the function, even in production code? Is there a means to turn them off? What's the runtime overhead of a "turned off" contract (even if it's just an if-test per condition, that can still add up)? And what happens if a contract fails - is it an exception/traceback (which is often unacceptable in production code such as services)? The lack of any clear feel for the cost of adding contracts is part of what makes people reluctant to use them (particularly in the face of the unfortunately still common assertion that "Python is slow" :-() Paul