[Steven D'Aprano] > You should look at the state of the art in Design By Contract. In > Eiffel, DBC is integrated in the language: > https://www.eiffel.com/values/design-by-contract/introduction/ > > https://www.eiffel.org/doc/eiffel/ET-_Design_by_Contract_%28tm%29%2C_Assertions_and_Exceptions > > Eiffel uses a rather Pythonic block structure to define invariants. > The syntax is not identical to Python's (Eiffel eschews the colons) but > it also comes close to executable pseudo-code.
Thank you! I forgot to mention this (or look into how other languages solve this problem). I saw your example syntax in the recent DBC main thread and liked it a lot. One thought I keep coming back to is this comparison between doc string formats <https://bwanamarko.alwaysdata.net/napoleon/format_exception.html>. It seems obvious that the "Sphynxy" style is the noisiest, most verbose, and ugliest format. Instead of putting ":arg ...:" and ":type ...:" for each parameter and the return value, it makes much more sense to open up an Args: section and use a concise notation for type. The decorator-based pre and post conditions seem like they suffer from the same redundant, noisy, verbosity problem as the Sphynxy docstring format but makes it worse by put all that noise before the function declaration itself. It makes sense to me that a docstring might have a markdown-style syntax like def format_exception(etype, value): """ Format the exception with a traceback. Args: etype (str): what etype represents [some constraint on etype](precondition) [another constraint on etype](in_line_precondition?) value (int): what value represents [some constraint on value](precondition) [some constraints across multiple params](precondition) Returns: What the return value represents # usually very similar to the description at the top [some constraint on return](postcondition) """ ... That ties most bits of the documentation to some code that enforces the correctness of the documentation. And if it's a little noisy, we could take another page from markdown's book and offer alternate ways to reference precondition and postcondition logic. I'm worried that such a style would carry a lot of the same drawbacks as doctest <https://bemusement.org/doctests-arent-code> Also, my sense of coding style has been heavily influenced by [this talk]( https://vimeo.com/74316116), particularly the part where he shoves a mangled Hamlet Soliloquy into the margins, so now many of my functions adopt the following style: def someDescriptiveName( arg1: SomeType, arg2: AnotherType[Thing], ... argN: SomeOtherType = default_value) -> ReturnType: """ what the function does Args: arg1: what arg1 represents arg2: what arg2 represents ... """ ... This highlights a rather obvious duplication of code. We declare an arguments section in code and list all the arguments, then we do so again in the doc string. If you want your doc string to stay in sync with the code, this duplication is a problem. It makes more sense to tie the documentation for an argument to said argument: def someDescriptiveName( # what the function does arg1: SomeType, # what arg1 represents arg2: AnotherType[Thing], # what arg2 represents ... argN: SomeOtherType = default_value # what argN represents ) -> ReturnType: # what the return value represents ... I think it especially makes sense if you consider the preconditions, postconditions, and invariants as a sort-of extension of typing in the sense that it Typing narrows the set of acceptable values to a set of types and contracts restrict that set further. I hope that clarifies my thought process. I don't like the d-strings that I proposed. I'd prefer syntax closer to Eiffel, but the above is the line of thought I was following to arrive at d-strings. > >
_______________________________________________ Python-ideas mailing list Python-ideas@python.org https://mail.python.org/mailman/listinfo/python-ideas Code of Conduct: http://python.org/psf/codeofconduct/