On Sun, 22 May 2016 06:48 am, Erik wrote: > Let me tell you a story ;) <wibbly-wobbly-lines> Back in the mid-to-late > 1980s I worked with C compilers on hardware that could take several > minutes to compile even a fairly trivial program. They errored on > syntactically incorrect code and happily compiled syntactically correct > code. Sometimes the output of the compiler wouldn't execute as expected > because of "undefined behaviour" of some parts of the language (which > the compilers could quite legally accept but would not produce valid > code for - even illegal ops are fair game at that point). They would > create valid code for the valid syntax of buggy code ("if (x = y) { > foo(); }") without a whimper.
Don't get me started about C and undefined behaviour. Fortunately, Python has nothing even remotely like C undefined behaviour. > At that time, we had a program called 'lint'. [...] > And now, today, the compilers all do far more than the original 'lint' > program did in almost zero time every time some source is compiled. It > is free; it is not something one has to remember to run every so often. This is certainly not the case for Python. With C, you run your compiler+linter once, and it builds an executable which can then run without the compiler or linter. With Python, *every time you run* the code, the compiler runs. The compiler is the interpreter. It can, sometimes, skip some of the compilation steps (parsing of source code) by use of cached byte-code files, but not all of them. Including a linter will increase the size of the compiler significantly, which much be distributed or installed for even the smallest Python script, and it will have runtime implications re compilation time, execution time, and memory use. If you make the linter optional, say, a Python module that you install separately and run only if you choose, then you have the status quo. > So, back to Python ;) > > The responses of "we can all write suspect/bad/ineffectual code - so > just run the linter" takes me back those 30 years to when we HAD to do > that with our C code too ... > > There must be a better way. Yes. And the better way is... don't write a language where you NEED a linter because the language specification is so fecking *insane* that no human being can reliably write correct code without running into undefined behaviour which *can and will* have effects that propagate in both directions, contaminating code which is correct in unpredictible ways. https://blogs.msdn.microsoft.com/oldnewthing/20140627-00/?p=633/ One difference between C and Python is that most of the things which Python linters look at don't actually have implications for correctness. Here are a few of the features that Pylint looks at: * line length; * variable naming standards; * unused imports; * unnecessary semi-colons; * use of deprecated modules; and a complete list here: http://pylint-messages.wikidot.com/all-codes As you can see, most of the actual errors Pylint will pick up would result in a runtime error, e,g, opening a file with an invalid mode. Most codes are for code quality issues, related to maintenance issues, not bug detection. Coming back to for...else with no break, the behaviour is perfectly well-defined, and does exactly what it is documented as doing. It's hard to see that it is a "bug" for something to do what exactly what it is designed to do. If somebody, for their own idiosyncratic reasons, wants to write: for x in seq: spam() else: eggs() (Note: I've done this -- see below.) and the language insists on a break, they will just pointlessly defeat the compiler: shutup_stupid_compiler = False for x in seq: if shutup_stupid_compiler: break spam else: eggs Thus entering an arms race where the compiler is seen as something to be silenced rather than something that helps you. I said that I've written for...else with no break. Why would I do such a thing? Because I wanted to clearly mark that the code in the else was a unit of code that went with the for-loop. Code displays varying levels of cohesiveness. Python lets you group related code in four levels: - the function/method; - the class; - the module; - the package but sometimes you have code which is smaller than a function that needs to be considered as a unit, but is not enough to justify putting it into a function. When that happens, we usually delimit it with comments, or sometimes even just a blank line: code that goes together different bunch of code that goes together So, when I had a bunch of code that included a for-loop, and something immediately after the for-loop, I could have written: for x in seq: block code that goes with the loop different bunch of code but I thought it communicated the grouping better to write it as: for x in seq: block else: # runs after the for code that goes with the loop different bunch of code I've since changed my mind. That's too subtle and too idiosyncratic for my liking. It clashes with the keyword "else", which I maintain is badly named. If it was named "next", which I maintain describes what it does much better, then things might be different, but given the status quo, I've gone back to doing it the old-fashioned way, with a comment. But the point is, that's a matter of *taste*, not a matter for the compiler. If somebody else wanted to do it my way, well, that's between them and whoever else works on their code. You probably wouldn't want the compiler to raise a syntax error because you put a blank line or a comment somewhere the compiler writer disapproved off. For example, some people insist that the first line of code must follow immediately after the docstring, some prefer to leave a blank line: def spam(): """Docs""" code def eggs(): """Docs""" code Your suggestion to raise a syntax error in the case of for...else without break strikes me as no different from the idea that we should raise a syntax error if there is/isn't a blank line after the docstring. (Choose one.) -- Steven -- https://mail.python.org/mailman/listinfo/python-list