You shouldn't use tabulators to indent your code. Use spaces instead. Here's why.

Here's a piece of code (don't worry about the indentation style used, this method just highlights the problem).

    if (getGnome() == null &&
        getKDE() == null)
    {
        // do something
    }

Here's the piece of code with spaces marked with dots (.) and tabs marked with plus-signs (+), with a tab size of four.

+   if (getGnome() == null &&
+   +   getKDE() == null)
+   {
+   +   // do something
+   }

This is all fine and dandy, but what happens when someone uses a tab size of 8 to view your code? Remember, one of the arguments for using tabs is that you can use whatever indent level you like independent from other developers.

+       if (getGnome() == null &&
+       +       getKDE() == null)
+       {
+       +       // do something
+       }

Looks ugly as hell, doesn't it. Why, I hear you say, I'll just use spaces to line up getKDE() with getGnome().

+   if (getGnome() == null &&
+   ....getKDE() == null)
+   {
+   +   // do something
+   }

Then it will stay aligned regardless of the tab size.

Fine idea, but rather difficult to put into practice. You see, since both spaces and tabs are whitespace, you'll have a hard time seeing when those empty spots are tabs and when they are spaces. And if you happen to use a tab size of four, will you always remember to align your if()s with spaces? What about your while()s? Your for()s? Does the guy who uses a tab width of three always remember to align his code with spaces? If your editor offers automatic indentation, do you always want to go and correct it by hand? Wouldn't it be just much easier to always indent with spaces?


Use a RealTextEditor. Both Emacs and Vim can be persuaded to use tabs for indentation and spaces for alignment.

In Emacs, the <tab> key indents the current line according to syntactic rules; in Vim, the key is =. No one in their right mind inserts tabs or spaces by hand.


To extrapolate "Tabs are evil" from the above examples is quite a leap, to say the least.

The first example above represents a misuse of tabs and a misunderstanding of the position that tabs should always be used for code block indentation. Here's why:

The indentation of the second part of the if clause is not a new code block and is thus not candidate for code-block-indentation. If (and it is a big "if") the author wants to separate the two parts of the if clause on different lines, he should do so with spacing that is conscientious to the indentation strategy. Specifically to this code example, a tab should be used to represent the original indentation of the if statement, and spaces used to align the second part of the clause with the first part. The key is recognizing the difference between indentation and alignment. Here's what I'm talking about:

+   if (getGnome() == null &&
+   ....getKDE() == null)
+   {
+   +   // do something
+   }

The spaces (represented by .) are used to align the getKDE() call with the getGnome() call, not to indent another block level. That is an important distinction, and failing to recognize and observe it is the fault of a lazy coder, not the fault of the principle of "tabs for indentation."

As for the second example, well that is simply a matter of laziness and lack of attention to details. The second if statement and the throw statement are simply indented wrongly. Again, that is not a reflection of the strategy -- rather it is the reflection of the total lack of a defined strategy on the part of the code's author. Don't blame the strategy that he obviously doesn't adhere to ...

The benefits of using an all-tabs strategy for indentation (not alignment) are outlined briefly at http://rizzoweb.com/java/tabs-vs-spaces.html and many other places.


Unfortunately this mixture of tabs and spaces:

+   if (getGnome() == null &&
+   ....getKDE() == null)

...is more evil than tabs alone. Do not mix tabs and spaces in the same source document, it complicates editing. Whatever nifty rule you dream up and would like everyone else to follow, mixing invisible characters that behave differently is absurd. Pick one of them and stick to it consistently. It so happens that spaces are necessary to fine alignment and also sufficient to all purposes. Tabs are not sufficient for fine alignment and they are not necessary either since spaces can be used instead.


Newsflash: your editor might mix tabs and spaces intentionally. Say we auto-indent the following code with tabs of size 8:

+       if (getGnome() == null &&
+       ....getKDE() == null)
+       {
+       +       // do something
+       }

Those spaces on the second line are the only way for whatever program we're using to shift the second line 12 columns to the right. It is impossible to use tabs all the way, since 12 is not a multiple of 8.

The alternative is of course to constrain the indentation to multiples of the tab size, which "looks ugly as hell" according to the original poster, because you cannot have any alignment. So using tabs, there are only two possibilities:

  1. Tabs and alignment, in which mixing of tabs and spaces is unavoidable. You might as well mix them sensibly.
  2. Tabs and no alignment, in which the indentation is always a multiple of the tab size, and the code is fugly to some.

To avoid mixing tabs and spaces, you must either constrain the indentation style, or use spaces only. If you want both tabs and alignment, you must mix.


More Discussion#

Indenting isn't to prettify stuff, it's to show structure. You yourself agree with me in that you complain about someone who used different tab width to you confusing you with the structure of your function, the problem you demonstrated wasn't remotely related to tabs (using pure hard tabs would have caused no problem), it was related to mixing tabs with spaces.

The following was presented as being a justification for spaces over tabs, because if you set the tab width to 8 (rather than 4) then the second line of the 'if' no longer lines up:

+   if (getGnome() == null &&
+   +   getKDE() == null)
+   {
+   +   // do something
+   }

This is a silly argument, you further indent the second line of the 'if' to indicate that it is a continuation of the line above. The fact that with tab = 4 spaces they happen to line up is, to me, completely irrelevant. I do exactly the same thing with multi-line 'while' statements, which don't line up in the same way to start with.

+   while( foo &&
+   +   bar )
+   {
+   +   //
+   }

I do agree that anyone who mixes spaces and tabs deserves to be spanked. Anyone who has the time to waste making stuff line up like you seem to want is wasting their employer's money.

Printing was presented as another (IMO spurious) counter-argument to the use of tabs, it is only an issue if you are piping directly to lpr, any competent text editor will use the current setting of tab width before submitting the page to the printer (I don't care if emacs doesn't do it, emacs is an amazing toy, and I use it quite a lot but it's thoroughly incompetent). If you are using lpr directly you can easily knock up a shell script to do the substitution for you. I edit my code orders of magnitude more than I print it, why would I care about minor inconvenience for something so rare?

Publishing was presented as another facet of this. Batch processing your book only once before it is sent to the publisher makes even more sense!

End of line comments are icky, once they are run onto multiple lines you force your preference of tab width on everyone else. If I have an end of line comment that needs to be edited then I will always move it to the line before, indented to the same degree as the statement itself.

The bottom line (to me) is that using spaces for indenting is selfish. You may like 8 spaces indent, or 2, or something else entirely, but I personally find both 8 and 2 awkward to read.

If you used tabs to do the indenting then I can adjust my editor (or rather, rely on the default).

If you used spaces then I have 3 choices (in reverse order of preference): overcome my aversion (only if I'm getting paid), reformat using tabs (manually or otherwise), or abandon it as poor code (code written in a manner not designed to be understood by it's reader is automatically poor).


"Anyone who has the time to waste making stuff line up like you seem to want is wasting their employer's money."

Never, ever work for me, then.

-- JanneJalkanen


Here's another example, from an actual piece of code (method names have been changed to protect the innocent):

    public void setDate( String d ) throws Exception {
        if (d ==  null || !(d.length() > 0 )) return;
            if( anotherCheck(d) ) {
                this.date = d;
                return;
            }
            throw new Exception("Illegal date");
    }

Because I happened to be using a different tab length from the original author, it took me a few moments to realize what the code actually does ... Thanks to the confusing indentation, and the mix of tabs and spaces in the code. (Please, don't comment on the throws Exception part here -- it's very bad style. Go to ExceptionHandlingInJava to see more. Actually, that method looks quite ripe for refactoring ... Let's analyze that method more deeply in RefactoringSetDate!)

Don't use tabs. Tabs are evil. So, go find the "replace tabs with spaces" setting of your favorite editor/IDE.

Orefa has more on the subject.


True Story
A programmer I knew (who shall remain nameless) would type in spaces for his alignment. After a couple of blocks in, he would be pounding away at the space bar. Using three spaces for every level of indentation.

public class SomeClass {
...private String m_someString;

...public void setSomeString(String someString) {
......m_someString = someString;
...}

...public static void main(String[] args) {
......if (args.length == 0) {
.........showUsage();
......} else {
.........doSomethingWithArg(arg[0]);
......}
...}
}

Three bloody keystrokes for each level of indentation. Three! What's worse, he would "refactor" other's work to suit his &!%$ed up style.

We had him shot.

As a personal preference, I use tabs because it is, quite frankly, more efficient. One tab, one level of indentation. Two tabs, two levels of indentation. Pretty simple if you ask me. Plus, if you use a RealTextEditor, it can accomodate others with whatever funky settings they prefer (e.g., 1, 2, 3, 16, 32 "spaces" for every level of indentation)...

If you really feel strongly about it, get jalopy or some other code beautifier that converts tabs to spaces.


"Three bloody keystrokes for each level of indentation."

Fortunately modern editors now simply converts a tab keystroke to 4 spaces (which seems to be the most commonly-used indentation value) or other selected value.

Tab lovers who like to change the appearance of other people's code can also use jalopy and also change everything else they don't like about the original code, not just indentation. If you want the freedom to alter code appearance, be serious about it and use a proper tool. Tabs are not a proper tool. They introduce an unknown into your source code that causes too many unnecessary problems.


Tabs are inanimate characters incapable of good or evil. But they should be considered harmful, moreso than goto statements ever are. You don't need a fancy IDE editor to convert tabs to spaces as you type. VIM and others easily take care of it. One thing not mentioned above is how tabs effect the hard copy printout. You think all your lines are <= 80 columns, but think again: they <= 80 "characters", the tab being 1 char but N columns where N is 8 as far as the printer is concerned.


I don't understand this example and why tabs are to blame for the code being confusing.

    public void setDate( String d ) throws Exception {
        if (d ==  null || !(d.length() > 0 )) return;
            if( anotherCheck(d) ) {
                this.date = d;
                return;
            }
            throw new Exception("Illegal date");
    }

The confusion over which 'if' condition is controlling the inner block of code is caused by several factors but the most naughty of these is using a single line if-then statement.

Give the original author a smack on the hand and add braces around the first 'if' branch ...

    public void setDate( String d ) throws Exception {
        if (d ==  null || !(d.length() > 0 )) {
           return;
        }
            if( anotherCheck(d) ) {
                this.date = d;
                return;
            }
            throw new Exception("Illegal date");
    }
... and (despite the code not being indented properly) control over the inner block becomes clear.

You can also choose to blame the position of opening braces. If you adopt the standard of placing opening braces on a new line then the start & end of the inner block becomes obvious:

    public void setDate( String d ) throws Exception
    {
        if (d ==  null || !(d.length() > 0 )) return;
            if( anotherCheck(d) )
            {
                this.date = d;
                return;
            }
            throw new Exception("Illegal date");
    }
Even without braces around the first 'if' branch, the second 'if' branch is more clear and easier to read, although many disagree with this convention, but let's not go there.

I really can't see how changing the tab size has caused the mis-alignment. If the code is correctly indented in an editor using 4 tab spaces it'll be correctly indented if you open it in an editor using 6 tab spaces. That's the advantage of using tabs.

The example given is more likely to occur if two developers are using spaces to indent. If one author using 4 spaces indentation writes the following:

(1x4)....public void setDate( String d ) throws Exception
(1x4)....{
(2x4)........if (d ==  null || !(d.length() > 0 )) return;
             [etc]
(1x4)....}
The danger is that another author using 6 spaces indentation comes in and adds code indented at a different level:
(1x4)....public void setDate( String d ) throws Exception
(1x4)....{
(2x4)........if (d ==  null || !(d.length() > 0 )) return;
(2x6)............if( anotherCheck(d) )
(2x6)............{
(3x6)..................this.date = d;
(3x6)..................return;
(2x6)............}
             [etc]
(1x4)....}
If both developers use tabs this kind of problem never occurs.

--Steve Battey, 21-Feb-2007


If you are mixing indent sizes in your code you deserve all the trouble you get - with spaces, everybody uses the same indent within the same project, and those who refuse to abide by it should not simply work in that project.

A programmer which is incapable of adjusting his working methods to a commonly agreed standard for a particular project is not a programmer - he's a diva.

The problem is that using tabs gives you the outward appearance of appeasing the diva within every programmer. But it just creates confusion.

--JanneJalkanen, 22-Feb-2007


Are you critising tabs for being flexible? Does this logic apply to other aspects of the development environment?
The developers on our project have tools like Tomcat and Ant installed in different places and we use enviornment variables to define their location.
Are we all divas? Should we have agreed a specific folder path for these tools? Or have we found a flexible solution to a common problem.

The advantage of tabs is that indentation can be changed to please the developer viewing the code. You can't argue that's a bad thing.
The disadvantage of tabs is that aligned text becomes mis-aligned when the tab size changes.

As you state in the previous comment:

  • If one indents with spaces then a project-wide agreement is needed to define how many spaces are used to indent, otherwise indentation becomes inconsistent.
But equally:
  • If one indents with tabs then a project-wide agreement is needed to define how many spaces are used per tab, otherwise aligned text becomes mis-aligned.
It's a trade off between the failings of both approaches, but I prefer tabs because it's easier to change the tab setting in your editor to fix alignment problems than it is to sift through code looking for lines indented by an incorrect number of spaces.

--Steve Battey, 23-Feb-2007


But don't any IDEs worth their salt do auto-indentation?

And if you fix the tab size, you lose all the flexibility. Note that indentation problems may stem from two developers using different tab sizes, and therefore choosing neither tab size helps in changing to the correct indentation.

The chief problem with the tabs is that you are essentially mixing whitespaces. And, if you fix the tab sizes in your project and make sure everyone uses the same indentation style, there is no point in mixing two whitespace styles.

Over my career I've had several cases with tabs messing up the codebase, simply because people don't realize they're sometimes putting in tabs and sometimes they're putting in spaces. A common case being a block indent being changed, and requiring realignment of some lines. After several people have worked in the project, the code base ends up being very confusing (because many times strict guidelines are not enforced), and someone needs to spend time fixing the indentation of others. I've never had any problems with spaces (except with people complaining about having to use spaces). Spaces are simply more tolerant to error, especially against newbies and divas.

--JanneJalkanen, 23-Feb-2007


"Note that indentation problems may stem from two developers using different tab sizes, and therefore choosing neither tab size helps in changing to the correct indentation."

Do you mean 'alignment' here instead of 'indentation'?
On one hand, tabs are perfect for indentation. It's a single character that developers can choose to size as they wish. If we were to write all statements on one line (i.e. didn't use any alignment, only indentation) I'm sure we'd all use tabs. Of course some statements would be illegible on one line, so that situation is hypothetical. But it highlights the difference between indentation and alignment.
On the other hand, tabs used for alignment do cause problems. But any editor will allow you to change the tab width setting and thereby re-align the code.

I hear your cries of suffering from indentation mal-practice. I've experienced them too, and it is very frustrating.
I've worked on projects where the coding standard stated spaces are to be used for indentation and there's always been someone who will have their editor configured to use tabs, causing a mix of tabs and spaces.
I've also worked on projects where the coding standard stated tabs are to be used for indentation and there's always been someone who will have their editor configured to use spaces, causing a mix of tabs and spaces.

The cause of mixing whitespace depends on your standard.
If you're trying to only use tabs, spaces are evil[1]. If you're trying to only use spaces then tabs are evil[1].
In my experience it doesn't matter what character you use for consistent indentation, you can expect someone to break it. And you should expect to need a code beautifier at some stage to fix those problems.

[#1] Evil relative to the world of programming. Tabs can't be blamed for all horrors known to mankind!

--Steve Battey, 26-Feb-2007


Look, it's very simple:

Using tabs to align text vertically (not block indentation) is relying on a side effect of a particular tab length. Relying on side effects is a big no-no, and you really should know better. If the implementation has a significant chance of variance, you must NEVER rely upon a particular one being used. Code block indenting works fine with tabs because the tab size doesn't affect its readability. Code line alignment doesn't work with tabs because changing the tab size breaks it.

But more importantly, anyone whining about someone using spaces instead of tabs or tabs instead of spaces should be fired for wasting everyone's time. The solution? Add to your process the following: ALL code checked in MUST first be run through this specific beautifier with this specific set of settings defined by the STANDARD for the company you work at (and you must be prepared to explain any exceptions). Don't have a standard? Then your first task is to get one!

People will make mistakes. Formatting errors will occur. Do you REALLY want to waste man-hours hunting down and changing formatting by hand, something a computer can do in less than a second?

Once your process involves a code beautifier with sane settings, the tabs vs spaces issue disappears, as if by magic.

- Karl

Add new attachment

Only authorized users are allowed to upload new attachments.
« This page (revision-64) was last changed on 06-Jul-2010 15:01 by 38.98.193.18