Spaces and Tabs

July 3, 2009

Like emacs vs. vi and what line you put your braces on, the issue of spaces versus tabs for indentation will always be a holy war among programmers. I’m from the always-use-spaces camp, but that’s not what this blog post is about.

Pretty much any editor worth its weight in gold (which is not very much) has a spaces/tab setting whereby you can hit the tab key and it inserts enough spaces to get you to the right indentation level, saving your wrists from tapping the space bar dozens of times and getting RSI. So if you’re a spaces guy like me, go with that setting.

And if you’re a tabs guy, use only tabs. Don’t mix the two, that will only lead to trouble when you’ve got someone else who uses a different tab size. You have to be extra-careful in order to make it look right at all tab sizes. Take the following, for instance, where [TB] is a 4-space tab, [-TAB--] is an 8-space tab, and _ is a space:

// 4 spaces:
[TB][TB]return Matrix(1, 2, 3,
[TB][TB]______________4, 5, 6,
[TB][TB]______________7, 8, 9);

// 8 spaces:
[-TAB--][-TAB--]return Matrix(1, 2, 3,
[-TAB--][-TAB--]______________4, 5, 6,
[-TAB--][-TAB--]______________7, 8, 9);

Getting this right is hard, especially since some editors (I’m looking at you, Visual Studio) like to re-indent things with tabs whenever they darn well feel like it.

Oh, and then there’s that whole semantic whitespace thing with Python. Can we please have our from __future__ import braces not throw a SyntaxError some time soon, Guido? Using tabs with Python is just asking for trouble. PEP 8 helps, but how many people actually read PEPs?

Well, I seem to have been rambling on about spaces and tabs on longer than I intended. Don’t mix spaces and tabs.

So the reason I started writing this post. Getting back to that. No really. I was editing a makefile the other day, obtained from a source which will remain nameless. Makefiles are notorious for being cryptic hard-to-maintain build systems filled with arcane syntax. Makefiles are so bad that there are a gazillion tools out there whose only purpose is to generate Makefiles: automake, cmake, qmake, Perforce Jam, and many more, though to be fair most of these tools are targeted at producing cross-platform software.

But let’s say you’re not using any of those fancy-pants tools because you’re a masochist, or more likely you’ve inherited a build system from a masochist. So you’ve got a makefile that you need to edit. I ran into this situation the other day. I fired up emacs, made my changes, and went to save it.

But something curious happened when I did so. emacs gave me the following message: “Suspicious line 50. Save anyways?” Its makefile-mode apparently installs a hook that checks your makefile’s syntax when you go to save it. Really handy. I wish other major modes did the same, although doing so may add an unacceptable delay to saving, particularly with languages with hairy syntax such as C++.

It turned out that line 50 had a mix of spaces and tabs indenting it. Hard tabs are meaningful in target specifications. In this case it didn’t end up mattering semantically, since it was in the middle of a multiline variable declaration, but I fixed it anyways to use spaces. I was also editing another makefile for which emacs gave a warning which had a blank line with spurious spaces. Again, not meaningful, but it was nice for the heads-up.

When editing a makefile in makefile-mode, emacs highlights trailing whitespace, but that’s not good enough for me. I happened to have a snippet of elisp code in my .emacs file that highlights all hard tabs. This made it especially easy to identify the problem in the offending line 50 in the makefile. I generally keep it on, but sometimes when I’m working with an all-tabs file it gets bothersome, so I turn it off. It’s amazing how code can have an awful mix of tabs and spaces all over the place as many different coders have touched it over time, each with their own preference for space and tabs.

Without further ado, the snippet. Just plop this baby in your .emacs file, and enjoy seeing your tabs burning bright on your screen:

; Draw tabs with the same color as trailing whitespace
(add-hook 'font-lock-mode-hook
  '(lambda ()
        '(("\t" 0 'trailing-whitespace prepend))

I found this snippet somewhere online, but I’ve lost the source. If you can point me to its source, I’ll gladly attribute it. And I just realized my syntax highlighter plugin doesn’t support any variant of Lisp. That’ll need to be fixed at some point, since there will likely be more elisp snippets posted here in the future. But until then, you’ll have to deal with broken syntax highlighting (currently highlighted as C++ code). At least there’s an even number of single quotes.

Update: Syntax highlight success! Source code for the highlighter can be found here.

Update 2/23/11: Plugin updated for Syntax Highlighter v3.x.

Comments are closed.