Elm-format: Notes on 4-space vs 2-space

Created on 23 Apr 2016  ยท  35Comments  ยท  Source: avh4/elm-format

I recently came across some old code that had been formatted using a previous version of elm-format that used 4-space indents (per @laszlopandy's original style guide) before the recent release switched to 2-space by popular vote.

When I hit Save and watched it switch from 4-space to 2-space, I was struck by how much less clear the "shape of the code" (to use @evancz's term) became. It makes me think 4-space is the right way to go, based on how they both look for actual, non-contrived production code.

I took some before/after screenshots (blurred both because it's proprietary code and to emphasize the "shape of the code" aspect):

Update.elm 4-space โ†’ 2-space

update

View.elm 4-space โ†’ 2-space

view

Model.elm 4-space โ†’ 2-space

model

discussion

Most helpful comment

for me 4 spaces is a waste of screen real estate, especially on laptops. it might a bit more readable, but 2 is readable enough for me, and allows me to edit code using a 3 columns layout (model, update, view). Just looked at a typical view function of my project: with 4 spaces, with a let block and three nodes deep, line start at character 28.

If we switch to 4 I'd reaaaaally love an option for 2 :)

All 35 comments

I prefer the two spaces myself, but I believe the right solution here would be to use Tabs instead of spaces. Most editors will allow anyone to set a tab widths to whatever looks best to you, without affecting committed code.

Somewhat relevant discussion from gofmt from when the authors locked it to tabs only. https://github.com/golang/go/issues/7101

Tabs are syntax errors in Elm, so that's not really an option. ;)

On Fri, Apr 22, 2016, 4:04 PM Victor [email protected] wrote:

I prefer the two spaces myself, but I believe the right solution here
would be to use Tabs instead of spaces. Most editors will allow anyone to
set a tab widths to whatever looks best to you, without affecting committed
code.

Somewhat relevant discussion from gofmt from when the authors locked it
to tabs only. golang/go#7101 https://github.com/golang/go/issues/7101

โ€”
You are receiving this because you authored the thread.
Reply to this email directly or view it on GitHub
https://github.com/avh4/elm-format/issues/158#issuecomment-213619225

I agree that the code with 4 spaces is more readable. But using 4 spaces is very inconvenient, sometime you need to remove or add the spaces by hand, which means a lot of typing. For this reason I rather have 2.

But why do we even use spaces? For me the right solution would be to push to use tabs instead as they allow for developer preference. This would require changing the Elm compiler. It seems to me like Elm would work really well with tabs.

I know there are strong opinions on this, but they are mostly cargo culting, I haven't seen a really strong argument for spaces over tabs.

I haven't seen a really strong argument for spaces over tabs.

I think the most convincing argument is that code that mixes tabs and spaces becomes truly awful to read. But that doesn't apply when the entire file is being automatically formatted to use tabs.

People will use spaces (and not elm-format) when they're just getting started, so ideally the compiler would support all spaces or all tabs, but not mixing.

As much as I've sworn by spaces, I do like the idea that tabs lets users pick between two and four spaces.

One thing to consider about tabs is that GitHub formats them into 8 spaces. This means a modest 4-level deep indentation (function - let - function - body) would mean 4x8 = 32 spaces.

One of the common things I do when reading an elm function is skip to the in block, read it, and then pop back up to the let block if necessary. You can see in Richard's Update and View files that there are big let blocks, and that matches our experience at Pear Deck too.

So, if you take that as a major use case for humans reading Elm, I agree that the four spaces make it much easier than two. You can try it yourself - just try glancing really fast between let and in. I think there are probably other major use cases for which two would be better.

OTOH, if I'm trying to solve this particular use case from a UX perspective, I wouldn't start with spaces. I'd add markup to my editor coloring the blocks in a margin, or use haskell's where instead of let..in, etc. I think maybe spaces are really only for the compiler, not for humans, and if we want to solve human problems then spaces might not be the place to start.

But why do we even use spaces? For me the right solution would be to push to use tabs instead as they allow for developer preference.

Emphasis mine. This is the biggest argument against tabs. ๐Ÿ˜‰

A: "Hey, half your code runs off my screen. It's really painful to read. Can you please keep it to roughly 80 characters per line?"
B: "What are you talking about? Every line I write fits under 80 characters. Look at my screen."
A: "Oh, you're using two-space indent for tabs. I'm using four."
B: "Whatever, not my problem. Change your editor settings to two and it'll be fine."
A: "Whoa, why should I have to change just to make your code readable? Why don't you change _your_ settings to four? Then you'd see how crazy long your lines are."
C: "Excuse me, but I use 8 spaces for tabs, and I can barely read the code either of you write. You both need to change."

Even if they weren't syntax errors, adopting tabs would destroy a major selling point of elm-format: preventing arguments like this. ๐Ÿ˜„

I think tabs are DOA for this reason.

I agree that the code with 4 spaces is more readable. But using 4 spaces is very inconvenient, sometime you need to remove or add the spaces by hand, which means a lot of typing.

Whoa, this is the opposite of my experience! Even when using 2 spaces, I never find myself double-tapping spacebar to indent or double-tapping backspace to de-indent.

I assume this doesn't come up when using your normal text editor of choice...when do you find it coming up? Let's talk about that.

I think tabs are DOA for this reason.

Definitely a good argument against tabs, but I wonder if your team can agree on an 80 char limit then you can probably agree as well on the visual width of tabs. Usually linters that enforce max width also take a parameter for the tabs width. Then this because a team preference.

I assume this doesn't come up when using your normal text editor of choice...when do you find it coming up? Let's talk about that.

When editing source code this is not a huge issue as long as Elm format is running. But if elm format is not present they 4 spaces is an issue.

One example is when for what ever reason elm format is not running. If I indent things too much and then want to remove indenting I find myself hitting the backspace sometimes. Even with all my shortcuts to indent, unindent in my editor, I end up in the situation where I need to remove the spaces by hand. I have been doing some Rust lately and find the 4 spaces indentation quite annoying.

Another example, trying to use http://elm-lang.org/try is painful because of this, I use tab and a tab appears which is not allowed, so I end up indenting by hitting spaces, 4 would make this terrible. Technically this has nothing to do with this issue as you could use 2 spaces there, but once you start using 4 spaces in you Elm code you want that same formatting everywhere.

If anyone is manually indenting by hitting spacebar multiple times instead of just the tab key... Please change your editor!

@eeue56 https://glot.io/ and http://elm-lang.org/try, they insert tabs when you hit tab, this behaviour is hard to change and changing those editors is not an option.

These are important to consider because we are not discussing elm-format just in the context of Sublime, Vim, etc. We are discussing here a global community style for writing Elm code. So then when I share some Elm using those tool I want it to follow the common style.

elm-lang/try puts spaces in.

Right, thanks for correcting me. But the idea is that when we don't have access to tools for automatic indenting, indenting by hand shouldn't be too painful.

the idea is that when we don't have access to tools for automatic indenting, indenting by hand shouldn't be too painful

I dunno, it seems like optimizing for the environment you'll spend 99.99% of your time in makes more sense than accommodating the 0.01% case, ya know? ๐Ÿ˜‰

Yeah, I'm also unsold on this being a real problem

https://glot.io/ [ ... ] insert tabs when you hit tab

Incidentally, I tried out glot and discovered that it does indeed insert tabs, but when you hit Run it converts them to spaces...specifically four spaces. ๐Ÿ˜ธ

for me 4 spaces is a waste of screen real estate, especially on laptops. it might a bit more readable, but 2 is readable enough for me, and allows me to edit code using a 3 columns layout (model, update, view). Just looked at a typical view function of my project: with 4 spaces, with a let block and three nodes deep, line start at character 28.

If we switch to 4 I'd reaaaaally love an option for 2 :)

@etaque curious - for your 3-column layout to work, do you keep lines to 80 characters or something significantly lower?

@rtfeldman around 80:

capture du 2016-04-27 23-32-07

same with 4 chars:

capture du 2016-04-27 23-37-05
To be honest, I expected worse.

Yeah it seems like basically everything fits in either version. ๐Ÿ˜„

Trying out 4 spaces on the current collection of real-world example files in the test suite. Here is how the maximum line length changes going from 2-spaces to 4-spaces:

screen shot 2016-05-09 at 10 41 30 pm

| File | 2-space indent | 4-space indent |
| --- | --- | --- |
| elm-lang/examples/random.elm | 57 | 63 |
| elm-lang/examples/Spelling.elm | 58 | 62 |
| rtfeldman/dreamwriter/RightSidebar.elm | 63 | 67 |
| elm-lang/examples/websockets.elm | 65 | 69 |
| rtfeldman/dreamwriter/LeftSidebar.elm | 66 | 76 |
| rtfeldman/dreamwriter/WordGraph.elm | 72 | 78 |
| rtfeldman/dreamwriter/Editor.elm | 73 | 75 |
| elm-lang/examples/time.elm | 74 | 80 |
| elm-lang/examples/http.elm | 79 | 85 |
| evancz/start-app/StartApp.elm | 89 | 95 |
| elm-lang/websocket/WebSocket.elm | 104 | 118 |

The worst file, elm-lang/websocket/WebSocket.elm, should be ignored because it has crazy formatting due to using lambdas with infix operators https://github.com/avh4/elm-format/issues/33#issuecomment-167204434

The next worst, evancz/start-app/StartApp.elm, is due to this line in a let block, which seems like a good candidate for wrapping to multiple lines or refactoring:

inputs =
    Signal.mergeMany (messages.signal :: List.map (Signal.map singleton) config.inputs)

The next worst, elm-lang/examples/http.elm, is due to a hardcoded URL which really should be extracted to a variable.

The remaining example that reaches an 80-char line length is elm-lang/examples/time.elm, which is due to this expression which arguably should be split to multiple lines or refactored:

line [ x1 "50", y1 "50", x2 handX, y2 handY, stroke "#023963" ] []

Based on the goal of improved visual scanning, and on the feedback from people who have tried both on large Elm projects, it seems worth trying 4-spaces in the next alpha release.

The impact on max line length is less than one might expect because the biggest impact is on let blocks, and those are rarely nested inside of other let blocks. The most deeply-nested code tends to be data structures (lists, records, and tuples), and there is less impact on those structures than expected because the following is correctly indented both for 2-space and 4-space indentation:

[ div
    [ text "" ] ...

I thought the consideration of ease-of-typing is a good one. But investigation of that seems to support 4-space indents as well. Most editors seem to have a default configuration set to 4-space tabs rather than 2-space tabs. In addition, due to the code example above, the 4-space indent seems more natural in most editors' default configurations because you always need to tab once to indent properly (with 2-space indent configured, you sometimes need to tab twice to get the proper indentation.)

To me, the 4-space versions look very oddly disconnected, like they are not related thoughts.

Also, if the two-space switch was made by popular vote, it really sucks to overrule it by fiat.

elm-format is still in alpha, so opinions are still being collected. The difficulty in getting opinions is that only people who disagree are incentivized to participate. I believe we need to try the switch in order to get balanced feedback.

Also worth noting that the original release was 4-space; people advocated for trying 2-space as an experiment in the 0.2 release. ๐Ÿ˜„

2 spaces FTW!

Many years ago I was a 4 space guy. But, about 4 years ago a job forced me to use 2 spaces. I was very upset and hesitant. My eyes were accustomed to easily scan blocks of verbose and curly-brace-heavy JavaScript, which was made easier by much more indentation than only 4 spaces. After about a week, I was hooked and never turned back.

But, that was JavaScript. We have a much more beautiful language to look at with Elm. Here are my _whys_ for 2 spaces (Disclaimer: This is OPINION):

  • I most often work split screen on a 15" Macbook Pro, code on the left, tests on the right. In Sublime Text that's about a margin of 95 in the config (which just so happens to be where I feel code gets too long). It's obvious and stated above that there doesn't leave much room horizontally when doubling the indentation.
  • Often indentation isn't the issue that one should jump to first. Lines of code often creates the most unreadable files (anything over about 100), followed by line length. IMO, indentation is a distance 3rd for readability issues.

    • I do believe that scannability is an unfair metric on which to gauge this decision. Scannability grows easier over a very short period of time (like an hour).

  • @crazymykl states _"To me, the 4-space versions look very oddly disconnected, like they are not related thoughts"_ and I very much agree with that statement! I have fallen in love with the _Elm style_ and how things just line up.
type alias SomeAlias =
  { thing : String
  , anotherThing : String -- 2 spaces here feels nice with the 2 space indentation
  }

and

-- 2 spaces everywhere feels like vacation!

view model =
  div
    []
    [ div [] []
    , div [] []
    ]

-- vs

div
    []
    [ div [] []
    , div [] []
    ]
  • 2 spaces keeps a visual continuity. The 4-space _div_ looks so disconnected. I'd highly recommend you ask someone who has experience designing visual interfaces for their opinion. We all might be surprised by what they say!
  • and last _and_ least, it's too hard to type 4 spaces into a Github comment.

I'm strongly against constantly changing the amount of spaces (4 -> 2 -> 4). While good tooling ignores whitespace, some tools see such formatting change as a 100% diff (looking at you, Bitbucket). It's really annoying to have to make feature branches just for whitespace update when elm-format (or the people behind it) changes it's mind again.

Maybe this time around whitespace changes can be coupled with Elm 0.16 -> 0.17 refactoring, but even that's not a 100% diff logically and will cause grey hairs when a work project forces you to use tools that are not great with whitespace.

TLDR: Please just choose something and stick with it.

There are 3 currently valid positions:

  1. I have a very strong preference towards 4-spaces
  2. I have a very strong preference towards 2-spaces
  3. I have a very strong preference for consistency.

I would expect that the third group outnumbers any of the first two. If that's the case, Evan should use benevolent dictatorial power to just name what he wants as the default and as soon as possible, all code in elm-lang/core should be converted to that default, ending this discussion once and for all.

All future attempts to restart the discussion should be short-circuited to "this has been discussed thoroughly and a decision on this topic has been made."

As for tabs, the only massively adopted programming language that uses tabs is Go and that is not because tabs have virtues that make them the undisputed best choice, that is because a decision has been made and this is what gofmt outputs.

Ping @evancz - input appreciated!

If I understand this correctly, the bit of code that controls number of spaces is one line:

spacesInTab :: Int
spacesInTab =
  4

Is there a reason why we can't have this be a configuration option? I do not like 4 spaces, hence I forked this repo and made the change in mine. It would be a shame if that's the only way we can change this setting.

See previous post by pdamoc - the desire for consistency is stronger and more popular than the desire for n spaces. I know I greatly appreciate the "save file, get _the one single canonical formatting_" aspect of elm-format. And the purpose of the tool is to save us from these unproductive debates. Use the time to go write good code.

Have I missed this point in the discussions above?: I have yet to see an Elm library source file in core 3.0.0 or 4.00 that is formatted w/ 4 spaces per tab. They are all 2 spaces per tab. Why are we considering switching when 2 spaces is already the convention?

I'll be honest: my preferred style is 2 spaces/tab for the following reasons:

  1. Elm style guide says to keep your code vertically distributed so that diff programs work more effectively to find what you're looking for. Hence, 2 spaces organize indentation fine when the lines are shorter.
  2. Since Elm lines are shorter, 2-spaces allows me to see more editor panes adjacent to each other.
  3. The other languages I use all use 2-spaces.
  4. I just like 2 spaces.

BUT NONE OF THIS MATTERS!!!

What matters is that Elm is already 2-spaces and there's gotta be a compelling reason to change it now. I don't want to have to reconcile my code to match to an arbitrarily-changed 4-spaces. Such changes are jarring; leave it at 2-spaces where it was.

My 2 cents

Please use 2-spaces.

This is purely a personal preference, but I prefer 2 spaces over 4:

  1. I like when my code is compact. 4 spaces takes up a ton of extra real estate and, in my opinion, doesn't offer any benefits. Some people mentioned that the additional whitespace helps them visually parse their code - for me it's the opposite. The additional whitespace is distracting. It makes my update function look like a bunch of words scattered throughout the screen.
  2. Every piece of Elm code I've ever seen has had 2 spaces. It seems that the Elm community has implicitly settled on the convention of using 2 spaces - why change it?
  3. 4 spaces requires more typing. Typing/deleting additional characters is annoying.

Thanks @scottcorgan for the relevant counterpoints!

This issue seems ready to close. As @avh4 put it:

elm-format is still in alpha, so opinions are still being collected. The difficulty in getting opinions is that only people who disagree are incentivized to participate. I believe we need to try the switch in order to get balanced feedback.

Let's see where perspectives end up after people have spent time actually using it for awhile, and revisit for the next alpha release. ๐Ÿ˜ƒ

Thanks for creating this tool!

However, the unilateral decision to arbitrarily force everyone into a different coding standard than the one already agreed upon and used by the community and elm-core is poor form for a project that is a key part of many people's workflows. If you want to follow a different standard, please consider adding an option that you can override so you don't mess up everyone else.

Here's a tiny diff for anyone who wants to build their own elm-format that follows the existing standard:

diff --git a/src/Box.hs b/src/Box.hs
index 3975f4e..b31baac 100644
--- a/src/Box.hs
+++ b/src/Box.hs
@@ -247,7 +247,7 @@ initRow startColumn =

 spacesInTab :: Int
 spacesInTab =
-  4
+  2


 spacesToNextTab :: Int -> Int

To clarify the history here, 2-spaces was not chosen by popular vote. elm-format initially used 4-spaces, since that was the preferred style at the time. Some people had requested 2-space indentation, so I ran a survey to help me make an informed choice about whether or not to try 2-spaces.

Here is what the survey found:

  • 85% of people have only tried one style
  • 98% of people who have only tried one style prefer that style
  • of the people who have tried both styles, 15% had no preference, and the rest were evenly split between 4-spaces and 2-spaces

Since most people had been using 4-space indentation, we decided to try 2-space indentation as an experiment to give it a fair chance. The feedback I've received from people who have now used both for extended periods of time has been in favor of 4-space indentation due to improved legibility.

As for core libraries, many use 4-space indentation. elm-lang/core itself has historically used a mix of 2-space and 4-space indentation. They seem to have been moving toward 2-spaces, but I don't see anything official about that. It would be great to hear from an elm-lang/core contributor about that. Some examples:

Finally, the Elm Style Guide uses 4-space indentation. http://elm-lang.org/docs/style-guide

elm-format is currently labelled as an alpha release for good reason: the format may still significantly change before release. The point of having an alpha is to be able to try things out in the real world before locking them in. If having a big change is going to be a problem for you, you should avoid using elm-format until it is released. I've updated the README to try to make that more clear.

Was this page helpful?
0 / 5 - 0 ratings

Related issues

pdamoc picture pdamoc  ยท  8Comments

sporto picture sporto  ยท  7Comments

conradwt picture conradwt  ยท  8Comments

avh4 picture avh4  ยท  5Comments

rtfeldman picture rtfeldman  ยท  4Comments