Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Consider switching to tab-based indenting in new Rust edition #3003

Closed
clarfonthey opened this issue Oct 10, 2020 · 24 comments
Closed

Consider switching to tab-based indenting in new Rust edition #3003

clarfonthey opened this issue Oct 10, 2020 · 24 comments

Comments

@clarfonthey
Copy link
Contributor

clarfonthey commented Oct 10, 2020

Right now, Rust's standard formatting suggestion is four-space indentations. However, there are multiple reasons why tabs may be more accessible, including:

  • Some (potentially common) screen-reader configurations may read out multiple spaces instead of as individual units
  • Tabs are easily configurable for folks who need larger or smaller indentations for a variety of reasons
  • Probably others I haven't thought of

There already are standard ways (e.g. editorconfig) to make tabs display as a set number of spaces in editors, and switching to using tabs by default would improve the accessibility of Rust as a whole. So, we could still set a recommended size for tabs to be displayed as four spaces, while still preferring the use of tab characters in files.

Note that this would simply be the default suggestion, and folks can still use spaces if they prefer. And because of the stability guarantees of rustfmt, it would have to be done with an edition bump, which is potentially coming up in 2021.

One of the biggest arguments against using spaces instead of tabs is the ability to do visual alignment, which is actually suggested against in the default Rust guidelines. Since Rust is already essentially using four spaces in the same way as tab characters, I think it would make sense to switch to tabs as a whole for continuing one of Rust's core goals of accessibility.

Note: as clarified in a few comments here, whatever happens should be the result of working with folks who use assistive technology (screen readers, braille readers, font scaling, etc.) and seeing what is most accessible to them. However, I have a feeling that tabs will ultimately win out as they're much more easily configurable. The whole point is to heavily consider the option of switching to tabs, not simply assume that either that solution or the status quo is best for everyone.

@Lokathor
Copy link
Contributor

If we recommend tabs there's no value to be had in suggesting tabs be displayed as a specific size.

@clarfonthey
Copy link
Contributor Author

clarfonthey commented Oct 10, 2020

If we recommend tabs there's no value to be had in suggesting tabs be displayed as a specific size.

I think there would be, considering how we have tools like rustdoc which will render tabs at a certain size. It would make sense to standardise that. Plus, there could be value in cargo init adding an .editorconfig file.

@BurntSushi
Copy link
Member

Unfortunately, this is not very accessible for folks who use screen readers, since individual spaces have to be read out instead of a single tab.

Are there any experience reports from folks that use screen readers that conclude this? I recall seeing one that counter intuitively came to the opposite conclusion, but I can't remember where.

@aloucks
Copy link

aloucks commented Oct 10, 2020

I sympathize with the @clarfonthey's use case, but tabs in code are a never ending source of inconsistent rendering behavior. For example, C++ files sometimes render poorly in github due to the prevalence of tabs. I would hate to see Rust follow this route.

Are there any other options for folks using screen readers without regressing to using tabs?

@clarfonthey
Copy link
Contributor Author

Unfortunately, this is not very accessible for folks who use screen readers, since individual spaces have to be read out instead of a single tab.

Are there any experience reports from folks that use screen readers that conclude this? I recall seeing one that counter intuitively came to the opposite conclusion, but I can't remember where.

I know that newer IDEs like vscode are adding better support for space-based indenting, but this relies on the indenting working as expected. Simple typos like using three spaces instead of four while editing can result in the spaces still being read out. I personally have worked with a coworker around ~3 years ago who said this was the case, but even then, you can't expect every editor to work properly with these cases.

The most well known post about this is probably this one on Reddit where some visually impaired folks mentioned the ability to override display width in their editors was also a reason it's more accessible: https://www.reddit.com/r/javascript/comments/c8drjo/nobody_talks_about_the_real_reason_to_use_tabs/

So, using just screen readers as an example is probably underselling it, since that has workarounds.

@clarfonthey
Copy link
Contributor Author

I sympathize with the @clarfonthey's use case, but tabs in code are a never ending source of inconsistent rendering behavior. For example, C++ files sometimes render poorly in github due to the prevalence of tabs. I would hate to see Rust follow this route.

Are there any other options for folks using screen readers without regressing to using tabs?

Inconsistency in rendering in these cases is also an accessibility issue that needs to be fixed in renderers rather than just falling back to spaces. You're putting your desire for aesthetics as a well-sighted person over the desire for usability of a vision-impaired person, which is not the right approach.

Granted, tabs may not be the solution here and spaces may win out for accessibility (I personally doubt it) but this is very much the wrong lens to view this under IMHO.

Something, something, the curb cut effect, also.

@skade
Copy link
Contributor

skade commented Oct 10, 2020

Unfortunately, this is not very accessible for folks who use screen readers, since individual spaces have to be read out instead of a single tab.

Are there any experience reports from folks that use screen readers that conclude this? I recall seeing one that counter intuitively came to the opposite conclusion, but I can't remember where.

You might think of this comment, pointing out that the comment syntax is very accessible for users of braille reader displays, which are far more common in Europe: rust-lang/style-team#120 (comment)

So, essentially the problem is: changes around this should only be done if multiple people from the same affected group, using a variety of accessiblity methods have concluded this is a bad thing. Otherwise we run into the danger of accidentally following someones personal preference or ignoring that people use a number of different tools to solve the same problem. This problem gets harder due to the fact that usage of assistive technology is widely differing across the globe, because of differences in the healthcare system or just plain availability. As a project of global scope, we need to think along those dimension. A change like this is substantial, so it has to weighted.

Just to be clear: I'm not trying to push the problem away, but it's a common effect that abled people take the first voice they hear, generalise it and then pass this off as "we asked disabled people".

@clarfonthey
Copy link
Contributor Author

Couldn't have put it better @skade and I also updated the original post to clarify a few things re: what you said. <3

@LoganDark
Copy link

As far as I've heard, the only purpose of spaces is to force the indentation to look exactly the same regardless of where it is viewed. They are nothing but a visual tool, and the point is to make the indentation immutable. Any other argument can be shot down in seconds (file size, editor support, semantics, accessibility, flexibility, etc.). It looks like the screen reader issues are a side effect of this.

The nature of the tabs vs spaces debate is always extremely opinionated. I agree that tabs are a better solution, and have even managed to change some minds in the past. I particularly like the fact that one tab always equals one indent, and indentation can be differentiated from alignment (which would still use spaces).

Here's an example of using spaces for alignment (where is a hard tab and · is a space):

fn main() {
→   let·x·=·f(arg1,
→   ··········arg2,
→   ··········arg3);
}

I believe that's called a hanging indent, but don't quote me on that. There's also "smart indent", which uses both tabs and spaces to combine units of indentation with character alignment:

fn main() {
→   let·x·=·f(
→   →   ········arg1,
→   →   ········arg2,
→   →   ········arg3
→   ········);
}

Although, in my opinion, that looks kind of silly and wastes space. Imagine if the variable name were longer, or the function name. I personally use the "continuation indent" style, which doesn't align:

fn main() {
→   let·x·=·f(
→   →   arg1,
→   →   arg2,
→   →   arg3
→   );
}

With spaces, you are always aligning based on characters rather than indentation levels. It's a subtle difference, but I prefer to use units of indentation for indentation, and leave the character alignment to the tool displaying that code visually to the user. This also makes it easier for non-visual tools to parse indentation, such as screen readers.

@jyn514
Copy link
Member

jyn514 commented Nov 9, 2020

I'd like to bring up the absolutely staggering amount of churn this would cause. Imagine that you switch to Rust 2021 (or whatever edition) and run rustfmt - almost every single line of code in your codebase would be changed. There is the alternative to write a rustfmt.toml that explicitly asks for spaces, but that itself is churn, although much less of it. I don't see any major projects switching to tab-based indents just because rustfmt changed its defaults.

Is the benefit for new projects really worth all the noise it would cause for existing ones?

@LoganDark
Copy link

LoganDark commented Nov 9, 2020

Is the benefit for new projects really worth all the noise it would cause for existing ones?

Yes.

@clarfonthey
Copy link
Contributor Author

Is the benefit for new projects really worth all the noise it would cause for existing ones?

Again, you need to frame this from the perspective of accessibility. The benefit is that people who need it can now interact with your code without needing to perform additional modifications or use additional tools. The cost is a single commit which changes your indenting.

And again, this wouldn't be a sudden, unannounced change; it would come with a new edition, where you explicitly choose to use the newer edition over the old one.

Imagine a similar scenario where one entrance to a building is closed so that they can add a ramp. You could argue that, since most people don't use wheelchairs, this is unnecessary churn. But that'd be pretty rude to wheelchair users.

The only question we should be asking IMHO is to what extent this helps existing users, and if it makes the code more accessible. The effort to switch is a non-issue IMHO because of all the things I've mentioned here.

@LoganDark
Copy link

LoganDark commented Nov 9, 2020

Not to mention the non-accessibility benefits that tabs have over spaces (see my post above). It may be difficult for some projects to switch, but they'll be better off in the long run. And, of course, some will stay on spaces.

@calebcartwright
Copy link
Member

I'd like to bring up the absolutely staggering amount of churn this would cause

I think this is a really important point, and why I'm opposed to changing the default (regardless of what the value is). Independent of the merits/drawbacks of the two options, this proposal would be highly disruptive and impactful, particularly in larger/active projects, and I feel like there'd need to be an overwhelming super-majority agreement from the community to make such a breaking change. I do not get the sense that there's a majority consensus (much less an overwhelming one), and I'd suggest that's at least anecdotally supported by the reactions/comments on this thread.

I know this is a rather evocative topic that people feel very passionately about. I also believe the vast majority of folks are firmly entrenched in their respective camp convinced beyond a shadow of a doubt that theirs is the "right" answer and don't understand how anyone could disagree. Just remember though that most of those on the other side feel exactly the same, and very, very few can be convinced otherwise.

This topic has been debated at length, and I think the final conclusion from the original RFC is still a good summary:

Thanks all for the discussion here. With regards to tabs vs spaces, the matter is settled - there is pretty strong (though obviously not unanimous) consensus in the Rust community in favour of spaces, and we've discussed here the objective benefits of the two approaches, as best we can. I firmly believe that at this point there is no possibility of changing this decision, so it's not really worth discussing further.

To summarise:

* the style guide will recommend using spaces and not tabs,

* Rustfmt will use spaces by default,

* **Rustfmt will continue to support tabs as an option**, so if you are a tabs supporter you will still be able to use Rustfmt, just with some minimal configuration.

Yes accessibility is important and yes accessibility and the other pro-tab points mentioned on this thread were part of the discussions as the Style Guide was being codified, but ultimately the decision was made to default to spaces based on other factors and feedback.

IMO the fact that that default has now been in place for several years only makes it that much more difficult to reverse that decision. The incumbency advantage/status-quo bias do weigh heavily, and I feel like the calculus behind the original decision would have to have shifted dramatically to override both the original (and oft re-affirmed) conclusion and the subsequent now long-established status quo.

Based on my experience working with rustfmt and the Style Guide, I have not gotten the impression that the majority position of the community has changed.

@comex
Copy link

comex commented Nov 9, 2020

Again, you need to frame this from the perspective of accessibility. The benefit is that people who need it can now interact with your code without needing to perform additional modifications or use additional tools.

There is a serious dearth of evidence that this is actually true.

I particularly like the fact that one tab always equals one indent, and indentation can be differentiated from alignment (which would still use spaces).

I agree that combining tabs for indentation and spaces for alignment would be great in theory. In practice, though, many editors lack even the most basic support for mixed tabs and spaces, at least out of the box.

For example, try creating a file like this, but where <<TAB!>> is replaced with a tab character:

fn foo() {
<<TAB!>>xxxxxxx(one,
<<TAB!>>        two,
<<TAB!>>        three);
}

The above is assuming a tab width of 8; for editors that default to tab width 4, make the function name shorter. The idea is that the line containing two starts with one tab (for indentation), followed by a number of spaces that happens to be equal to the tab width (to align after the opening paren).

Then go to the end of the line containing two and press enter. The editor should automatically indent the next line to match. But will it reproduce the same mix of tabs and spaces, or will it convert the spaces to a tab?

I tested Vim, Emacs, VS Code, and IntelliJ IDEA under default settings (except for enabling automatic indenting in Vim, which has it off by default).

  • IDEA did the right thing by default.

  • Vim and Emacs did the wrong thing by default, but can be configured to do the right thing:

    • Vim has an option to fix this (but more advanced functionality like auto-alignment doesn't work).
    • Emacs has a downloadable package (that apparently does support smart auto-alignment).

    Still, most Vim and Emacs users probably don't have their editors configured that way and would have to learn how to do so.

  • VS Code did the wrong thing and I don't think there's any solution ([1] [2]).

Other editors, with smaller userbases and fewer features, are also likely to lack support. For example, GitHub's web-based editor does the wrong thing and, having only minimal configuration options, can't be configured to do the right thing.

You might argue that people should just rely on rustfmt to fix their indentation. But even if you do, it's going to cause problems if your editor is constantly butchering the indentation as you edit. Besides, some people prefer not to use rustfmt.

@clarfonthey
Copy link
Contributor Author

Again, you need to frame this from the perspective of accessibility. The benefit is that people who need it can now interact with your code without needing to perform additional modifications or use additional tools.

There is a serious dearth of evidence that this is actually true.

Which is why this issue is, again, focused on considering using tabs instead of spaces. Most of the established programmers who rely on assistive technologies live in niches where tooling is good because of the reasons mentioned. Again, using the ramp example, if you poll the residents of an apartment building and ask them how much they personally need a ramp installed, they will most likely overwhelmingly say they don't need one because the people who need a ramp won't live there.

I'm not pretending to be an expert on this subject but I've heard from a decent number of sources a decent number of arguments in favour of tabs over spaces, and because Rust so uniquely focuses on accessibility as a core motivation for the language, I think it's something worth talking more about.

Again, "churn" still seems overblown as a downside. Replacing space-based indentation with tabs is a one-time occurrence, which again would be explicitly opted into. If there are merge conflicts, running the conversion on conflicting code will resolve them. There have been much bigger changes made to large Rust codebases that didn't have nearly the same opposition, like how the Rust repo recently moved some folders from src/ to library/.

The fact of the matter is that, as far as simple tabs (not mixed with spaces) go, you'd be hard-pressed to find an editor that doesn't properly support it. And, Rust already discourages visual indenting, making mixing unlikely.

It's not a decision to take lightly, but it's also not one to discard lightly either. Majority vote isn't necessarily the best solution for accessibility issues.

@iago-lito
Copy link

I'm not familiar with huge projects and huge codebases, so I fail to represent how much 'churn' the switching represents. This is unfortunate because 'churn' is continuously brought as the reason not to switch.

My naive thought is that accomodating the change in a large project is just worth 1 commit, something like

$ cargo fmt
$ git add --all
$ git commit -m "Accomodate new tab-indent default."
$ git push origin master

which is not horrifying. Why am I wrong?

@jyn514
Copy link
Member

jyn514 commented Nov 10, 2020

@iago-lito because it causes merge conflicts. Look at the chaos in rust-lang/rust#67540 (comment), and then look at how many files would be modified by switching to tabs: https://gist.github.com/jyn514/b82af6ec47f30d4fc9cc87739b069d4f.

Doing that I realized I have another objection - rustfmt doesn't treat tabs properly! git diff -w shows 500 lines changed even though all the tabs are hidden - here's that diff: https://gist.github.com/jyn514/92071bd448290444d79d6f8fc94368c1

The issue is that rustfmt has opinions on how big a tab is, even if you don't, and re-wraps lines to match based on that. And it looks like it doesn't agree with git diff on how big a tab is either, judging by how far off the screen + |param| matches!(param.kind, ast::GenericParamKind::Lifetime { .. }), goes.

@scottmcm
Copy link
Member

And again, this wouldn't be a sudden, unannounced change; it would come with a new edition, where you explicitly choose to use the newer edition over the old one.

I don't think that makes a substantial difference here. We generally treat moving to new editions as something everyone actively working on their Rust code should do -- maybe not immediately, but probably within a year.

I think it's unlikely that we'd do something that a ton of people would make noise about, no matter how cargo fixable.

Why am I wrong?

We had to do something like this at my $RealJob to fix line endings. It's been a continual annoyance because git blame and friends don't always see through such changes. Ever over a year later I'm still in "Was that actually changed by John Smith, or is it just pointing at the whitespace change commit he did?" mode.

@rdebath
Copy link

rdebath commented Nov 20, 2020

On unix (linux) many things require or assume that tabs are every eight columns.
eg: XTerm (from the VT100 and other physical terminals), ls(1), pr(1), col(1), termios(3) -- Yes the linux kernel assumes tabs are at 8 and it cannot be changed only turned on or off.

Then there's all those tools that try to align a pointer in a error message with a line of source code printed before it ... basically every modern compiler. Most of them don't have the problems of Python of course, that's the only language I know offhand where the width of a tab is part of the grammar. But as soon as some editor start ass-uming that tabs are three spaces (or four or whatever) the display gets messed.

A tool doesn't even have to care about tabs to be impacted by this; just displaying the tab character is enough for a program to be impacted because your XTerm (and ever other terminal emulator) will by default assume that tabs are every 8 columns. What's more if you configure your emulator to change this, those error messages (and ls!) tend to stop lining up.

Where did this come from? Well, back in antiquity the reason for tabs existing was that long distance comms were running at 11 cps or slower. A printer could move it's carriage far faster, so the tabs allowed you to print on the right without having huge delays. The file size was never a significant difference. This is why I think tabs should be verboten in text files and the tab key should be treated like the other cursor movement keys generating spaces to do the right thing. I am, however, mostly okay with eight column tabs in files though, because, in general unix (linux) tools, that express a preference, all assume 8 columns.

@joshtriplett
Copy link
Member

See https://github.com/rust-dev-tools/fmt-rfcs/pull/9/files for the style team policy on reopening old issues.

This has been discussed extensively and exhaustively, and every single point raised in this thread has been raised in previous discussions. If genuinely new information were to come to light, we could consider reopening the topic. However, there isn't value in rehashing the many previous discussions on it.

This is an inherently controversial topic, and no answer is going to satisfy everyone. We needed to select a default. rustfmt provides configurability, for exactly this kind of reason.

@Jordandev678
Copy link

Apologies for posting to the closed bug but as someone has only just drawn it to my attention, it's only closed in December, and the style steam policy linked before closing explicitly says "unless they provide fresh information" I hope people won't mind too much.

To be clear I'm not intending to kick of this discussion again and re-open this right now; I just wanted to drop this here for the people involved in the discussion to be aware of so they can reference it along with the accounts on reddit etc. when it comes up again as this discussion across all languages often includes comments like those here saying that input from more people affected by this is needed before they could conscience making changes and I do not know of a better way to add my account to the record as someone directly affected than to post to issues such as this one. But I feel it's important as like most accessibility issues I suspect we're not a massive proportion and by the time most of us find out about these discussions they're "closed".

So to that end allow me to link to this post I made in rustfmt. As someone from the "this directly affects me from an accessibility standpoint" group here is a contemporaneous comment on my first experience with rust. rust-lang/rustfmt#4067 (comment) It was not endearing.

That's it, bye :)

@tombh
Copy link

tombh commented May 16, 2022

This thread came high up in my searches to find the current indenting recommendation. I suppose there won't be many more comments here, so for anybody else that's just interested in the conclusion and nothing more. As of May 2022 Rust's Style Guide suggests: 4 spaces

https://github.com/rust-dev-tools/fmt-rfcs/blob/master/guide/guide.md

@ferdinandkeller
Copy link

ferdinandkeller commented Feb 7, 2024

I came here for the same reason as @tombh. As of February 2024, the documentation is now available on rust-lang.org. And still recommends spaces, and explicitly not tabs 😕.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests