(I use spaces only because I try to follow common coding styles, like PEP 8, but I never gave it enough thought)
(I use spaces only because I try to follow common coding styles, like PEP 8, but I never gave it enough thought)
Aligning within a line can and should be done with spaces. There's good reasons against alignment in such cases -- for example, it creates git blame/git diff noise when reformatting due to having to update alignment on a bunch of other lines just because you introduced a variable one character longer than the others. Irrelevant, though; such alignment is perfectly fine to do with spaces in a context where you indent with tabs.
The other type of alignment is beginning-of-line alignment, which is indeed not doable with spaces. Some people recommend doing such alignment with spaces despite the tab indent (cf. http://dmitryfrank.com/articles/indent_with_tabs_align_with_...). It's a valid argument but I feel it's too much of an aberration to be taken seriously.
I personally find such alignment generally repulsive anyway. Take a look at the following code and tell me which method looks better:
Too many times have I seen such function calls where the space between the parenthese and the soft wrap leaves <10 characters to work with. And here we go with one small argument per line, every argument preceded by 70+ spaces. I know programmers who could fit video games in the bytes used for just a single function call like that.
But I'm with you: that kind of column alignment is harmful to maintainability, and I find it much less readable too.
Some time ago I posted a few examples of column alignment gone bad, from the Servo source code:
https://news.ycombinator.com/item?id=9469713
and also discussed alignment here:
https://news.ycombinator.com/item?id=9469713
Once you give up column alignment, there's no longer any real reason to prefer spaces, and you can gain the benefits of using tabs. As a side benefit, when you give up alignment, your code becomes just as readable in a proportional font as a monospaced font.
More details in my previous comments linked above, so I won't rehash them here. :-)
I remember that page, actually. It's a really good point that code alignment breaks proportional fonts, I never considered it. More points for accessibility I suppose!
If you're working with git on a non-whitespace-sensitive language, and this annoys you, you can use the --ignore-space-change option to avoid this.
That seems like a strawman to me. I would go with something like:
function() {
nested_code() {
some_very_long_function_call(
long_argument_one, long_argument_two,
long_argument_three, long_argument_four,
);
}
}(I wonder if this why your comment got downvoted? FWIW, I upvoted you for engaging in the discussion.)
Personally, I would do his second example like this:
function() {
nested_code() {
some_very_long_function_call(
long_argument_one,
long_argument_two,
long_argument_three,
long_argument_four,
);
}
}
In other words, once I get to the point of splitting up the call into multiple lines, I generally split all the arguments onto their own lines.Now all the arguments are lined up with each other, as they are in your example. This matches how I format multiline statement blocks: if I'm splitting the code to multiple lines, then I split it consistently on each argument. This way I don't have to worry about how many arguments fit on a single line.
Of course I'm not entirely consistent about this. :-) Take a function like CreateFile() in the Windows API. It has so many parameters, and you're likely to pass in NULL or 0 for so many of them, that it makes sense to bunch them up a bit to not use so many lines.
But even then I wouldn't start adding extra spaces within a line to make vertical columns out of it.
The second is better looking. I'd rather maintain the second.
But...
The first is easier to read. The shape of the code is enough for me to parse without effort. In the second, I have to "walk myself" through the code, even for this little example. I feel the effort required as soon as I have to start looking for the embedded commas.
So I usually choose something like the first, since time spent typing matters less than time spent thinking.
I maintain that if tabs are permitted, so are other ASCII control codes, like vertical tab, form feed (which is actually used in GNU code), and bell.
int foo(void)
{
<TAB>/* <BEL><BEL><BEL> This bit is really important. */
<TAB>...
}
<VT>
int blah(void)
{
<TAB>...
}
<EOT>
<EM>
:-)But I like your sense of humor, so you definitely earned an upvote from me - a flaming tab advocate!
(And I learned to program on a ASR33 Teletype - so I do miss those old control codes...)
The GNU coding standards request form-feed (\f or ^L) to separate code into logical pages.
https://www.gnu.org/prep/standards/standards.html#index-cont...
The support in editors is abysmal and doesn't work out of the box correctly for tabs (e.g. invisible whitespace).
I've never seen an argument for spaces that would hold iff all editors would have sane defaults for programmers. Of course, it's also bad that some programmers can't configure their tools correctly, but that is a complete different issue.
The best of both worlds would be "tabs for indentation, spaces for alignment" but as it is now, you only need one programmer with wrong settings to screw that up, so that's why most projects have settled on the most conservative setting.
If you do that, all of these issues go away. You can use tabs or spaces for indentation, and it won't affect your formatting. You can reformat the code to a different number of spaces, or switch from spaces to tabs or vice versa, and your code will still be perfectly formatted.
A good way to learn and practice this style is to switch your editor to a proportional font. Now you won't be able to use column alignment, and without even working at it you'll naturally start to explore an alignment-free style.
I've had many programmers react in shock when they see I write code in a proportional font, but when you don't use alignment it stops mattering what font you use.
With tabs you need to configure each and every tool you use to use the right indent (2? 4? 8?), with spaces, every tool just works, and copy/pasting a section of code to or from an issue or an e-mail or a chat tool just works.
It is a matter of code typography. When more than one developer is working on a code base, it helps if every one sees the same outline, because with varying amounts of indenting one persons preference aligns all parameters in a long important method call, whilst any other indenting breaks (part of) that format — code may look fine for one person, but jumbled for another with a different indent preference.
With editor support better than ever, using spaces isn't something you think about when coding; you just hit tab to indent and it inserts the number of spaces configured.
I like Python's PEP 8 in that respect. The language itself (and the syntax checking tools such as pyflakes) simply states the sensible default you aught to be using.
You mean like those times I would have to configure my editor so it inserts the exact amount of spaces required by the project I'm working on, for the project maintainers prefer 4-width to 2-width or 8-width? :)
You talk about typography but this is exactly what I underline in my article: Your preference is not everybody else's and I personally find 2-space code absolutely unreadable... while some companies adopt it as their internal codestyle.
My eyesight has been deteriorating for the past 10 years and I've had to increase my font and zoom sizes as well as line spacing every now and then. Compact 2-space code truly is a strain on the eye for me. If you're using tabs, you don't have to care about my eyesight, just like you don't care about my font size.
In short, the real issue with tabs is that you can't reliably use them for column alignment. But many of us have concluded that column alignment is a harmful practice, preferring indentation instead to show the structure of our code.
And once you give up column alignment, you can use tabs for indentation, and it just doesn't matter what tab size the person reading your code prefers. It will read just the same in any tab size and any font, even proportional fonts.
It's really quite liberating to stop using column alignment. :-)
> And once you give up column alignment, you can use tabs for indentation
You don't have to give up alignment for tabs if you like it occasionally; just indent with tabs and align with spaces. (I highlight leading spaces in a slightly different shade from the background to allow for this.)
It's impossible to use anything but spaces in LISP without going mad, and the editors like emacs do a fantastic job formatting the s-expressions. So spaces are very superior to tabs for some languages.
For languages with a syntax similar to C, it doesn't matter, the rant was taken out of context, and the rest is history.
Whatever you use, make tabs and spaces visibles in your editor and never, ever, mix them up for indentation.
In either case the line contains only 75 characters, of course, but that's a pretty pedantic non-answer: we care about horizontal screen space, not the number of bytes of storage you'd need.
(It's also high time we stop pretending wrap limits matter to the exact character. In most cases, they are and should be guidelines - we have evolved beyond 640x480 CRTs and 80 character terminals)
I suspect that it isn't much of an issue in practice for a few reasons:
1) I'd wager that most projects that have a hard 80-column limit also forbid tabs.
2) If a project does use tabs and has a hard line length limit, it can simply say that that limit is interpreted using a certain tab size (e.g. the most common tab size is probably 4 spaces).
3) In my own code, as I've mentioned probably too many times in this thread :-) I don't use column alignment, which is one of the main causes of excessive line length. Because I use indentation for multiline expressions, my lines of code tend to be a lot shorter than they would be with column-aligned expressions.
The first one might be a legitimate issue. The second issue, I've noticed, I've never had a problem with, even in heavily indented lisp:
- If your variable names are too long, they must not be obvious from context, and your function/method/block is doing too much. Refactor.
- Consequently, if the line is too long, perhaps it's doing a little too much; short lines with limited logic help with code comprehension the same way short methods do. Splitting code into multiple lines generously allows you to clearly indicate how parts relate to one-another.
My line width is 76 characters max to allow for 3 columns for line numbering + one space after it---if line numbering requires more columns that that, maybe your file's too big as well. Some will disagree on that last point, but I consider that in the same light as I do line length and function size. For OOP especially where there's one class per file, it's certainly a code smell if you have a long file.
Apparently nested JS runs faster with spaces.
I've always omitted the indent_size and tab_width settings from my .editorconfig files that specified tabs, because I wanted to let people view the code in their preferred default indentation size instead of one I specified.
(As I've mentioned too many times in this thread, I follow an indentation-only style with no column alignment, so you can view the code at any tab width without breaking the formatting.)
Now, just to make GitHub give a reasonable code listing, I'm having to add indent_size=4 to all my .editorconfig files. That's not a terrible thing, but I really would prefer to leave the choice up to the viewer instead of forcing 4-character tabs.
And seeing as 80 characters is still the normal line limit, because of window splitting, it does happen quite often.
If you stop using alignment and use only indentation for your multiline statements, these issues go away. Your code will be just as readable with any tab size, and even in a proportional font. And your line lengths get much shorter in the process.
For specific examples, see the other comments in this thread from scrollaway and myself, in particular the Servo source code I linked to.
No, thanks, I'd rather use spaces that don't require any workarounds.
Not in the slightest. The disadvantages of column alignment have nothing to do with whether you use tabs or spaces.
I don't recall for sure, but I think I was using spaces for indentation at the time that I stopped using column alignment.
Column alignment has the same problems if you indent with spaces: it leads to excessive line length, it's unfriendly toward source control diffs, it's fiddly to maintain, it mandates the use of a monospaced font, and I find that it harms readability compared to the alternative of using indentation.
Take a look at the Servo code examples I linked to in another comment. Are the column-aligned versions a better way to format code than the indented versions?
Here's another way to look at it. If the column-aligned way of writing a multiline function call or expression is such a good thing, why don't we also format blocks of statements this way:
if( foo == bar ) { if( baz == moo ) { console.log( "yes" );
this.that = true; }
else { console.log( "no" );
this.that = false; } }
instead of: if( foo == bar ) {
if( baz == moo ) {
console.log( "yes" );
this.that = true;
} else {
console.log( "no" );
this.that = false;
}
}
It is probably obvious that I prefer the latter, as would most developers. So why not apply the same formatting principle to expressions that we apply to statements?"Many of us" prefer spaces for that reason and that's why it has become the de facto standard.
But look, my real point here is that column alignment is detrimental in several ways, and indentation is a better way to illustrate your code structure - both for statements and expressions.
Using indentation instead of column alignment isn't a workaround for anything - it's just a more practical, readable, maintainable way to format your code. This question really has nothing to do with tabs or spaces.
While we're on the matter of user prefereces and numbers: Most style guides recommend spaces as lined out in my other post.
>Google, Microsoft, Apache and NASA for C-family languages, Crockford and almost every other web-related style guide I've ever seen recommend the use of spaces. Apple is a notable exception.
That doesn't make them right, but I'd like to know how you came up with the "many of us" in the first place, because there are far more developers who use spaces (https://ukupat.github.io/tabs-or-spaces/), and it's not even close.
Has it? I wasn't informed. I know it has in the Python community, because of pep8 mainly, but a lot of communities have settled on tabs (Lua for example, and for a long time PHP until recently).
I'll paste here what I replied to someone off-thread, regarding "why" anything ever becomes a de facto standard.
> I would bet quite a bit that personal indent preferences are driven by whatever the default is on the editor of choice of the person in question. I would equally bet that you can correlate the tab defaults on editors/IDEs widely used in specific communities (Visual Studio for Windows C-family stacks, PyCharm for python, Eclipse and its little family for java, etc) and the general preference of that community.
Chicken and egg problem. Spaces aren't standard because they're preferred; they're preferred because they're standardized by editor defaults. Developers that don't have a particular preference grow into those defaults.
Google, Microsoft, Apache and NASA for C-family languages, Crockford and almost every other web-related style guide I've ever seen recommend the use of spaces. Apple is a notable exception.
It seems you're the vocal minority: https://ukupat.github.io/tabs-or-spaces/
In fact, having done a lot of Lisp programming recently, I wanted to format some Java code using that style too, but IDEA's code formatter is too limited to allow me to do that.
I don't see any reason not to. Your example is pretty ugly though, as it's not particularly aligned. What about:
if( foo == bar ) { if( baz == moo ) { console.log( "yes" );
this.that = true ; }
else { console.log( "no" );
this.that = false; } }It breaks with proportional fonts, and... well, if we wanted to right-align things in code, our non-document editor would probably support it by now, don't you think?
It's not right-aligned, I've aligned the "." method accessors, ";" statement delimeters, etc. into the same column, and treated "else {" as a single token.
It would be even nicer to align the two pairs of statements more directly, but that ends up overflowing 80 characters, e.g.
if( foo == bar ) { if( baz == moo ) { console.log( "yes" ); this.that = true ; }
else { console.log( "no" ); this.that = false; } }
> It breaks with proportional fontsProportional fonts break many "in-band" layout schemes; e.g. ASCII-art layout used in plaintext email. I think "out of band" layout schemes, like CSS, would be overkill for code layout; and certainly more effort to implement than making the editor manipulate ASTs instead of character streams.
A couple of problems I see here:
What happens if you have more than one dot, like foo.bar.method()? Which dots do you line up?
And note that the else isn't aligned with its matching if.
I suppose another alternative would be to line things up like this:
if( foo == bar ) { if( baz == moo ) { console.log( "yes" );
this.that = true; }
else { console.log( "no" );
this.that = false; } }
Now the if and else line up, and so do the statements in the dependent blocks.But with either of these aligned formats, I'm finding it pretty hard to visualize which if statement goes with which block of statements.
To me, this is one of the fundamental problems with column alignment: once you start doing it, it's too easy to start fiddling with all of the possible things you might align. And it really doesn't help the reader visualize the code structure except in the simplest cases.
Also, you're in for a maintenance headache when someone changes foo to moreMeaningfulName. Now what? Move everything farther to the right?
With an indentation-only format, you can change any of the variable/function names without breaking the formatting at all.
I certainly agree that it can cause problems, e.g. with diffs, extraneous decisions, etc.
I only tend to do it when there's commonality between the lines (more than trivial ones, like "there's a dot"); e.g. aligning the "=" in a bunch of assignments, aligning the arguments in calls to the same function, etc.
> Also, you're in for a maintenance headache when someone changes foo to moreMeaningfulName. Now what? Move everything farther to the right?
I tend to follow the following process:
- Preserve the existing alignment (e.g. "move everything over")
- If any lines grow longer than 80 characters, split them
- If any already-split lines shrink to less than 80 characters, remove the split
- If you spot a nicer pattern, try it
- If there's no pattern anymore, "fall back" to not doing any alignment; consider inserting blank lines if the statements are very different or the lines are very dense
I've thought a few times about making an auto-layout script, which would run files through a language-agnostic "nicely aligned" fitness function, and make a bunch of language-specific semantics-preserving edits to try and maximise this score. It's quite low on my TODO list though ;)