blogs by Gio

Tabs or Spaces?

  • Posted in ๐Ÿ‘จโ€๐Ÿ’ป dev

“Tabs or spaces” is one of these age-old computer science preference issues (like whether you use Vim or Emacs1) that gives people a binary preference they get to pick and then get very attached to, due more to sunk costs and personal identity than anything else. (Good thing that only happens with unimportant stuff.)

I was thinking about this the other day, and I realized that I have an opinion about this, but it’s actually the opposite of what I do. And it’s not because of filesize, or encoding, or anything like that.

(First off, because I’ve actually heard this, nobody is actually physically hitting their spacebar four times. Any decent editor is going to have “spaces mode” where hitting the Tab key inserts four (or two, or whatever) spaces.)

There are many argumments people have come up with on both sides of the issue. Tabs and spaces are both in ASCII, so whether your file is encoded in ASCII, UTF-8, or something bad, both characters take up the same amount of space. When we indent with spaces, though, we use four spaces, not one, so using spaces to indent makes the indentation four times as large to store. This argument is a bit silly, but it’s got numbers in it, and people like that2.

Why you should actually use tabs to indent files๐Ÿ”—

If you’re writing a Real Professional Document in Microsoft Wordโ„ข, and you indent your paragraphs by just pressing space until you think the line looks indented enough, your editor will send your document back with a note saying “You’re incompetent, go back to baby school for babies”, or somesuch. If you want to indent a section, you indent it, you don’t add spaces; spaces and indentation represent fundamentally different things. “Spaces” are different than “space”.

Tabs specify an indentation level, NOT physical space. They’re higher level abstractions, in that sense, than spaces. The tab key was originally for tabulation, or specifying a column in a table. When you specify tabs, you’re not talking about the physical distance (whether in units of pixels or characters) of the next character from the left side of the window, you’re talking about a hierarchical level.

But the biggest argument in favour of tabs is accessibility. Since tabs represent a conceptual indentation level, text editors can render them however the user wants. Some people are comfortable with two-space tabs, some people might require more than four characters worth of space. Some people might want something fancy, like dropped lines signifying the indentation level. I’ve even seen some very clever things done with hanging tabstops, where indented lines are positioned dynamically based on other lines, rather than arbitrarily positioned away from the start of the line.

Why I don’t๐Ÿ”—

I’m a python developer, and in python, whitespace is a big deal. Whitespace is semantic in python (which is wonderful, by the way), and so it matters a great deal how your lines are indented. Take this code example:

def getItems(obj):
    for itemList in obj['items']:
        for item in itemList:
            yield item

Say someone edits this method so it uses yield from syntax, instead:

def getItems(obj):
    for itemList in obj['items']:
		yield from itemList

This is better written, except that it won’t run, because “someone” indented4 line 3 there with tabs instead of spaces, which doesn’t match the line above it, and that’s a full-on syntax error3 in python. The python compiler5 won’t even run the file.

You can test this by typing this into the interactive prompt. You won’t even get a chance to call the function, it’ll immediately raise a TabError (or IndentationError on awful garbage versions of python that need to be thrown in the trash).

>>> def getItems(obj):
...     for itemList in obj['items']:
...             yield from itemList
  File "<stdin>", line 3
    yield from itemList
TabError: inconsistent use of tabs and spaces in indentation

This is just one example — and I think it’s a pretty good one — of a case where you need to know if some whitespace is a tab or not.

And that’s the crux of the problem. If I’m working on a file that has tabs in it at all, I need to know what’s a tab and what’s a space while I’m working on it. Both tabs and spaces are non-printing characters, which means my editor is going to have to indicate where the tabs are, somehow. Let’s see how they do that:

Github tab viewer

Oh. Oh. That’s not good at all. Where did all that dirt come from?

And that screenshot is from Github’s pretty HTML5 code viewer; doing something like this on a terminal, or in an environment that requires any amount of contrast, fills your screen with distracting clutter.

There are Vim settings to replace tab characters with arrow characters, and Emacs comes with a standard whitespace-mode to handle differentiating whitespace characters. That looks like

Vim tab characters Emacs whitespace-mode

Oh. There’s a problem here.

The amount of additional visual information you need to have on screen if your document contains tab characters amounts to unnecessary clutter. That’s all extra information you have to be be consciously processing.

Beautiful is better than ugly. Clutter is bad and bad for you. I always end up avoiding the problem altogether by just always using spaces.

At least it’s for an actual reason that simplifies my workflow, such that if I used tabs instead, it would cause actual problems. It’s nice to at least have a reason. Since most of my code is either just for me or part of a codebase that already uses spaces, I don’t feel too bad about it.

  1. the correct answer is emacs, no blog article needed 

  2. support hbomberguy on patreon and then watch this video 

  3. Technically, tabs and spaces are both allowed in python, but they’re not compatible. Line 2 is indented with 4 spaces, but line 3 is indented with 2 tabs. Python won’t try to convert between the two (which is good), it’ll just note that there’s no “matching” indentation level, because if you start indenting with 2 tabs, you need to have been on 1 tab before. 

  4. Pelican would have automatically converted that tab character into four spaces when it rendered the document if not for some elaborate workarounds on my part. Oh well. I guess we know their take on the issue. I also had to manually override tab-width, which is 8 spaces by default for some reason? 

  5. Python is a compiled language, the people who told you otherwise were lying and you should tell them so. 

Howdy! If you found my writing worthwhile, the best thing you can do to support me is to share an article you found interesting somewhere you think people will appreciate it. Thanks as always for reading!