Significant Indentation: Mixing Tabs and Spaces

I really like the significant indentation syntax due to land in the next release, but given how it is impossible to tell what mixture of tabs and spaces there are in a chunk of whitespace, would it be possible to make the presence of tabs a compile error?

I experienced the ability to mix the 2 as confusing in haskell when I was just starting using it (then I dropped tabs altogether), and even if it would be better in Scala 3 (would it?), we can do much simpler than the below if the language is a bit more opinionated about this.

Indentation prefixes can consist of spaces and tabs. Indentation widths are the indentation prefixes themselves, ordered by the string prefix relation. So, so for instance “2 tabs, followed by 4 spaces” is strictly less than “2 tabs, followed by 5 spaces”, but “2 tabs, followed by 4 spaces” is incomparable to “6 tabs” or to “4 spaces, followed by 2 tabs”. It is an error if the indentation width of some line is incomparable with the indentation width of the region that’s current at that point. To avoid such errors, it is a good idea not to mix spaces and tabs in the same source file. (indentation.md)

I dislike how this inevitably opens up a tabs vs. spaces debate, so to try to short-circuit that: I’m with tabs in principle, this is what tabs are for, but spaces won, that’s what modern tools work well with (e.g. soft tabs in editors). Code with tabs looks like a mess in Gitlab for example, sometimes in IntelliJ too. Maybe it’s configurable, but that’s extra effort and friction, especially when talking about e.g. company Gitlab servers.

Significant indentation will not be a part of Scala 3. It’s just an experiment in the Dotty compiler

You will find it is not a problem in practice. If you mix tabs and spaces the compiler will give you an error with a very specific error message. Here’s an example, from one of our tests:

5 |    println(2)
  |    ^
  |    Incompatible combinations of tabs and spaces in indentation prefixes.
  |    Previous indent : 2 tabs
  |    Latest indent   : 4 spaces

If you get errors like that you will very quickly standardize on either all tabs or all spaces.

And: There’s no decision on significant indentation optional braces in Scala 3, but no ruling it out either. I am personally cautiously optimistic; we are making very good progress on a number of tricky details.

2 Likes

I don’t know, people can be quite stubborn when it comes to bikeshedding :slight_smile: But OK, even if it is a relatively small issue, is it counterbalanced by anything we gain if we allow both styles in the same codebase?

That error message is indeed nice and informative, no head scratching there, but the fact that it is a thing still might be an issue. I currently work with a code base full of tab indented Java files. When I change something not realising I’m changing one such file, the mixture looks like a mess outside my editor. Not a big issue in that case and can be left to be governed or not governed by in-house coding standards as it is just a matter of style in that case.

However, once whitespace gains meaning, and wrong combinations can get you bumping into compile errors on edits for no good reason… why not just disallow the variety to be able to have more defined expectations regarding the invisible parts of the unfamiliar code we are looking at?

It would be a quality of life improvement in my opinion, if I imagine finding myself in a remotely similar situation but in a Scala 3 code base.

Thanks for the clarification, I was a bit confused after going through the discussion on Github and reading @kai’s comment, looking forward to seeing how this goes.

The debate on tabs vs. spaces been hashed out so many times that it has been parodied on general-audience TV (HBO’s Silicon Valley). I think we’ve all heard all the arguments and no one is likely to be convinced to change their mind. I think this is one of those cases where it’s important for the programming language to not be opinionated in one direction or the other, or else it will alienate a lot of developers.

I will add that I don’t think that the fact that you can’t visually tell the difference between tabs and spaces gives any more legitimacy to tabs or to spaces for being the blessed indentation: one could as easily be surprised to find that a file is indented with spaces as they could be to find it indented with tabs.

1 Like

That’s my point though. Your message reads as if my main argument would be about tabs vs.spaces. I was arguing for neither of the above to be possible to happen.

Anyway, if I interpret the error message posted by @odersky correctly, within a single file you will be forced to choose. (I didn’t find under 3 minutes an editor on my PC that would do hard tabs so I ended up not trying how this works ) If that’s the case then this indeed is not that much of a problem, and might even be a good compromise (e.g. I would prefer that to the ruling going against my preference on the secondary issue of what whitespace should be blessed).

I am dead set against significant indentation, but I’m all for optional braces.

If they could throw in optional parens too, that would be a huge break-through, really sweet.

I’d recommend supporting tabs under -Xsource:anachronistic. The tabs issue comes up at work too frequently because any given tool chain fails to support tabs consistently, let alone line endings aka separators. If Scala could work toward eliminating tabs from source text by the end of the century, that would be a great boon to the next generations of coders. I learned tabulation on the mechanical typewriters in the office where my grandmother worked, approximately a hundred years ago. I think it’s fair to re-evaluate our typing habits every century or so.

2 Likes

Scastie inserts tabs and this causes errors. https://github.com/scalacenter/scastie/issues/445

I sure hope you are correct. If it goes with indentation over braces then that totally sucks. Is that what is really being considered? Staring at lines of code trying to figure out where blocks begin and end and making changes becomes a huge pain. Copy and paste, refactoring all become a pain. Situations where you have lots of indentation become asinine to the max with code running on and on outside the view, 4 indentations is 16 characters, leaving less than 60 to type code. Lack of braces and indentation is not what made python popular, but the switch can make Scala more unpopular almost over night.

6 Likes

“Optional Braces” is still in Dotty documentation: https://dotty.epfl.ch/docs/reference/other-new-features/indentation.html

I’ll repeat my concern here: will automatic scalafmt reformatting be supported in the new (identation based) syntax? scalafmt can reformat code to fit within given columns number, that is very useful for me (I don’t like the super long lines often produced by scalariform).

1 Like

Significant indentation was the most annoying thing which I had met when I started working with python.
Everybody says It just requires time to accustom. Ok I can accustom, but I really do not understand why so many people should always spend time to accustom.
How is it linked with the aim to make scala more simple for beginners?
If it were killer feature it would be clear. But after all it is very questionable for a dsl oriented high level functional language.

3 Likes

If indentation syntax is adopted, we (the Scala Center) will make sure that scalafmt supports it. This is not a concern.

3 Likes

While tooling is a concern, I’m a bit more worried that the feature freeze thread seems to indicate this will become part of Scala 3 without going through the SIP process, despite its controversial nature.

1 Like

All Dotty features do need to be approved by the SIP committee, it’s just that documentation pages on the dotty website are used instead of documents on the SIP website.

1 Like

I agree with making tabs an error. Most projects in Scala 2.x are already indented with 2 whitespaces – some enforced by Scalafmt, but not all.

If Scala 3 drops braces and adopts an indentation rule like an off-side rule, then the result should be more uniform code base across the ecosystem, not more diverse. If depending on the opensource project or corporate policies, we end up with a smörgåsbord of tab vs 2- vs 3- vs 4-whitespaces vs unholy mix, it would be a regression from the status quo.

If indentation is such a good idea that we are making every Scala codebase switch over, there should be a single Scala 3 style (for example, 4 whitespaces), and that should be strictly enforced by the compiler, much like running scalafmtCheck as part of compile task.

2 Likes

Making the compiler check indentation where it’s expected & standardizing the number -> absolutely great.

Significant indentation much less so. If Scala code needed to look like python code we could just write python. But let’s not rant.

Seems like this thing destroys some significant readability advantages, like double clicking near a brace to highlight a code block, e.g. where 2 tab indents are no longer obvious or during a refactor (paraphrasing of previous comments). Replacing that with with, then or end tags also has some silliness to it?

Should the feature still make it, it can’t be optional IMHO (so no -noindent). I recall this discussion, where a massively useful feature like -Yinfer-argument-types was dropped because it “changed the language”. While it worked fine in 2.11 and when used I found no ambiguity to it. But if you drop something like that to ensure “a standard language”, you surely can’t go down an avenue of making this one optional.

1 Like