Thoughts of the inarticulate.
My thoughts, which I'm no good at articulating.

Wednesday, November 12, 2008

VIM, Python and indentation

So, I enjoy the Python language.  It seems efficient with CPU and memory, comes out of the box with a large amount of libraries, has a lot of support and some high quality web frameworks (such as Django).

Of course, one cannot mention Python without mentioning indentation.  Initially it was one of the things that drew me to Python, as I liked the idea of consistent indenting producing more readable code across the board.  After plenty of experience with not so readable code with crazy source code formatting (please don't put your body of an if on the same line as the if! :P) this appealled to me.

However, it has taken some getting use to, and early on almost made me give Python away.  And some issues still mean I'm not 100% convinced, but I'm still enjoying using Python and will continue to use it.

So, just some things you should learn if you are new to Python and don't want to pull your hair out using it and its strict indentation:
  1. First, if you are using VIM, download this indent plugin for python.  The default is awful.
  2. How to show whitespace in your editor to find where indentation might have gone wrong (Python will tell you about it).  A common example is a tab mixed in with spaces.  In VIM this is accomplished with ":set list" (and :set nolist to turn off again).
  3. How to indent and unindent the current line.  In insert mode in VIM, the default is C-D to unindent, C-T to indent.  These are a must and save muchos time!!! In normal mode it is "<<" and ">>".
  4. Do NOT reindent big chunks of code unless you know what you are doing (e.g. in VIM using "=" on selections).  With Python you really shouldn't need to, since indentation actually affects how your program runs.
  5. Be careful even reindenting single lines automatically (using "=" in VIM for example).
This brings me to the point that I'm trying hard to get over.  I'm use to being able to select a whole file (of PHP for example) and getting VIM to reindent for me.  Or using a source code formatter to reformat the file.  Now, with Python this isn't necessary, considering file will always be properly indented.  I've have done it out of a reflex action, and the consequences weren't fun.  Just don't do this :)

However, if you in the middle of making some changes (e.g. removing a level of indentation) sometimes you do want to reindent a chunk of code.  Unfortunately, there just isn't enough information in the source code for an automatic reindenting algorithm to know how to correctly reindent.  Without being careful, this can cause significant changes (most likely errors) in your program.


1 if foo == bar:
2 print "foo equals bar"
3 if foo == zoo:
4 print "foo also equals zoo"
5 print "end of foo equals bar test"

If you use "=" in VIM on line 5 it will reindent it to the same level as line 4. Obviously this is an error.  I guess this is VIM reindent being too aggressive, but the point is such a subtle change can cause drastic changes in a programs execution.  Imagine a much more complicated example than above with more code at each indent level and (heaven forbid) more levels of indentation.

The fact that a developer NEEDS to be so careful about such a subtle thing with major consequences if they aren't, makes me wonder if Pythons handling of indentation blocks is really the best way to go about it.  Bad indentation in other languages makes it look like a mess, but still work.  Bad indentation in Python still looks ok, but won't work as expected.

That said, what it does encourage is less levels of indentation, and less code per indentation, which is what we should be all doing anyway.  

So to continue on, on how best to manage it, which are useful tips for all languages:
  1. Keep levels of indentation within a function to a minimum (I think keeping to 2 or below should be easy enough)
  2. Keep lines of code per indentation to a minimum.  This raises an interesting question about how many lines of code this should be.  I would say under 10 is ideal, 10 - 20 acceptable, and getting more than that means perhaps you need more functions.  I'm certainly guilty of that, however thinking of my nicest, easiest to work with code, under 20 lines seems like a good number to aim for (this is why squiggly brackets on a new line is the way to go people! Stop complaining about your wasted space and write concise functions! :P)
  3. Be very very careful when reindenting existing code.
  4. Write unit tests! They'll pick up any fuck ups. :)

Labels: , , ,


Post a Comment

<< Home