One of the longest unresolved arguments among developers is whether you should use tabs or spaces in your code. It is also difficult to find good discussion on the topic because it gets sidetracked by non-issues. This post makes two assumptions, so we can focus on what matters:
- You use a code editor which assists in indenting. Whether the file contains tabs or spaces, you just press Tab once to indent.
- The project is set up (e.g. through GitHub actions) to reject malformatted files, so problems like mixing tabs and spaces in the same file are caught.
The assumptions are important. Tab users often argue that they only have to press Tab once to add indentation, whereas pressing Space multiple times is unproductive. Space users often argue that tabs in files lead to broken code because they get mixed with spaces. In practice, these issues are easily resolved by using a proper editor, setting up a CI, pre-commit hook, etc.
After those arguments are resolved, what else remains?
An obvious benefit of spaces is that they result in the same reading experience everywhere. Whether you open a source file on GitHub, in your local editor, in the terminal over ssh, etc., the code looks is visually the same everywhere.
One of key benefits is that we know how the code will be rendered elsewhere. If the editor is locally set up to show eight-space spaces, the developer is encouraged to write much shorter lines to avoid unwanted automatic line breaks. However, if the project is set up to auto-format based on a two-space or four-space tab, those choices are often nonsensical.
It is much easier for everyone to share the same artistic vision when they can agree on how the code renders.
If you auto-format your code (and you should),
you almost certainly use a fixed column limit so that code past that limit is broken
onto the next line.
This also means that the project needs to define how many columns a tab is equivalent to.
In most cases, this is going to be 4
.
Setting the tab width in your editor to anything but the "standard tab width" of the project
offers an unpleasant writing experience.
If you set it to 8
, then you can write code significantly past the perceived column limit
without the auto-formatter taking any actions.
Conversely, if you set it to 2
, your code may be broken surprisingly early.
In almost every editor, tab width is a global setting that applies to all files. However, a reasonable width depends on multiple factors, such as the file type. For example, Markup formats like YAML, XML, etc. often use two-space indentation because they can be very deeply nested:
system:
config:
subsystem:
project:
name: "coolproject"
version: "1.0.0"
I have seen many markup files with ten levels of nesting/indentation in my life, and you wouldn't want to read these files with the default tab width of eight columns on GitHub.
On the other hand, GNU C projects use a tab width of eight. For C code, that is perfectly reasonable because functions aren't even defined in classes but at the top-level in the file, so it would take many levels of indentation to hit a column limit:
int f(int b)
{
if (true) {
return b;
}
}
The lesson here is that the file type, and possibly even the individual file dictates what a good indentation width is. The easiest way to make that choice per-file is to use spaces.
To be fair, some editors at least let you customize the width based on file type, but it would be a lot of work to configure this consistently across all your tools, if that's even possible. It's not possible on GitHub.
Every now and then, you may run into a piece of code that auto-formatters just can't get right. In those case, you can disable formatting for a code block, like with clang-format in C:
// clang-format off
int matrix[3][3] = {
{ -1, 0, 1 },
{ 0, 1, -1 },
{ 1, -1, 0 },
};
// clang-format on
In those rare cases, there is still a danger of developers accidentally mixing tabs and spaces, or improperly using tabs for both indentation and alignment. Spaces are idiot-proof because mixing spaces and spaces isn't an issue, and you cannot avoid the use of spaces entirely. When working in a large team, can you really rely on everyone being a good-enough whitespace engineer not to mess it up?