2016-07-11
Why Python can't have a full equivalent of Go's gofmt
I mentioned in passing here that people
are working on Python equivalents of Go's gofmt and since then
I've played around a bit with yapf,
which was the most well developed one that I could find. Playing
around with yapf (and thinking more about how to deal with my
Python autoindent problem) brought home
a realization, which is that Python fundamentally can't have a full,
true equivalent of gofmt.
In Go, you can be totally sloppy in your pre-gofmt code; basically
anything goes. Specifically, you don't need to indent your Go code
in any particular way or even at all. If you're banging out a quick
modification to some Go code, you can just stuff it in with either
completely contradictory indentation or no indentation at all. More
broadly, you can easily survive an editor with malfunctioning
auto-indentation for Go code. Sure, you code will look ugly before
you gofmt it, but it'll still work.
With Python, you can't be this free and casual. Since indentation
is semantically meaningful, you must get the indentation correct
right from the start; you can't leave it out or be inconsistent. A
Python equivalent of gofmt can change the indentation level you
use (and change some aspects of indentation style), but it can't
add indentation for you in the way that gofmt does. This means
that malfunctioning editor auto-indent is quite a bit more damaging
(as is not having it at all); since indentation is not optional,
you must correct or add it by hand, all the time. In Python, either
you or your editor are forced to be less sloppy than you can be in
Go.
(Sure, Go requires that you put in the { and } to denote block
start and end, but those are easy and fast compared to getting
indentation correct.)
Of course, you can start out with minimal, fast to create indentation;
Python will let you do one or two space indents if you really want.
But once you run yapf on your initial code, in many cases you're
going to be stuck matching it for code changes. Python will tolerate
a certain amount of indentation style mismatches, but not too much
(Python 3 is less relaxed here than Python 2). Also, I'm confident
that I don't know just how much sloppiness one can get away with
here, so in practice I think most people are going to be matching
the existing indentation even if they don't strictly have to. I
know that I will be.
I hadn't thought about this asymmetry before my editor of choice started not getting my Python auto-indentation quite right, but it's now rather more on my mind.
2016-07-03
An irritating little bug in the latest GNU Emacs Python autoindent code
I really like having smart autoindent in my editor when writing code, Python code included. When it works, autoindent does exactly what I would do by hand, does it easier, and in the process shows me errors in my code (if the autoindent is 'wrong', it is a signal that something earlier is off). But the flipside of this is that when autoindent goes wrong it can be a screaming irritation, as I flip from working with my editor to actively fighting it.
Unfortunately the latest official version of GNU Emacs has such an
issue in its Python autoindent code, under conditions that are
probably rare. To see the bug, set Emacs up with python-indent-offset
set to 8 and indent-tabs-mode set to t, and then enter:
def abc(): if d in e: pass # Hit return here:
If you put your cursor on the end of the comment and hit return,
autoindent doesn't add any indentation at all. It should add one
level of indentation. Also, once you have this code in a .py file
you don't need to set anything in Emacs; Emacs will auto-guess that
the indent offset is 8 and then the mere presence of tabs will cause
things to explode. This makes this issue especially annoying and/or
hazardous.
Some people will say that this serves me right for still using tabs for indentation in my Python code. I'm aware that there's been a general movement in the Python community to indent all Python code with only spaces, regardless of how much you indent it by, but for various reasons I have strongly resisted this. One of them is that I edit Python code in multiple editors, not all of them ones with smart autoindentation, and space-based indenting is painful in an editor that doesn't do it for you. Well, at least using generous indents with manual spaces is painful, and I'm not likely to give that up any time soon.
(I like generous indents in code. Small indent levels make everything feel crammed together and it's less obvious if something is misindented when everything is closer. Of course Python's many levels of nesting doesn't necessarily make this easy; by the time I'm writing an inner function in a method in a class, I'm starting to run out of horizontal space.)
PS: I suspect that I'm going to have to give up my 'indent with tabs' habits some day, probably along with my 8-space indents. The modern Python standard seems to be 4-space indent with spaces and there's a certain amount to be said for the value of uniformity.
(People are apparently working on Python equivalents of Go's gofmt,
eg yapf. This doesn't entirely
make my issues go away, but at least it would give me some tools
to more or less automatically convert existing code over so that I
don't have to deal with a mismash of old and new formatting in
different files or projects.)