I recently realized that we inherited a particular design decision from Elm—namely, that tab characters are disallowed—and never really discussed it here, so while I'm not advocating for or against changing the status quo, I am advocating for exploring the question explicitly :big_smile:
there is a massive thread advocating for the ubiquitously-used JavaScript formatter Prettier to switch to using tab characters for indentation by default instead of spaces. I know go fmt has been doing this for years.
tab characters do have a straighftforward performance advantage when it comes to parsing; \t is 1 byte, and multiple spaces are multiple bytes, so there's just less to parse if using tab characters
Whatever we do, I think we should pick 1 specific format and not be like python where both work, but not together.
Funny you mention that. It was one of the first things I tried when I started playing with Roc. Tabs always made more sense to me but years of Python and JS experience taught me to let that go :upside_down:
something that's partially an upside and partially a downside is that tab widths are configurable in many editors (and GitHub, now).
an upside is that different people with different indentation size preferences can adjust their tab widths according to their own preferences, rather than perhaps being unsatisfied with the enforced number of spaces.
a downside is that different people working on the same code base may see the code differently, which can have consequences like:
another consideration is that if we enforce "Tabs are only for indentation and can only be used at the beginning of a line (and maybe also in string literals, but that would be a separate discussion). Spaces are never allowed at the beginning of a line." - which is the design I would favor by default - I'm not sure how that rule would affect Roc code being embedded in other contexts, e.g. code snippets in .md files
if someone has their editor set to convert tabs to spaces, is it weird if their .md files have code snippets that get converted to spaces, e.g. because someone looking at that code thinks "whoa this Roc code is really indented strangely compared to what I'm used to"
(presumably it wouldn't be a compile error because there'd just be a syntax highlighter pass happening on code snippets in a .md file anyway)
I'm curious if anyone has relevant experience working in code bases that used hard tabs for indentation, e.g. in (or in any language, really)
I think the formatter at least should parse both and always output one
yeah I think the way to go would be to have the parser understand both but then report an error (or perhaps warning) if it gets the disallowed one
in general I'd like to make the parser more permissive in ways like that, especially for editor integration
e.g. if you have an outdented when branch, giving an error but still assuming you meant it to continue the current when branch (so the formatter can just fix it for you like it does in Rust)
I guess another downside is that tabs may be harder to type in some contexts (e.g. browser textareas) because the tab key has some other meaning
some relevant points here: https://github.com/ziglang/zig/issues/544#issuecomment-558881335
some interesting points about humans and editors mixing up tabs and spaces by accident - https://github.com/ziglang/zig/issues/544#issuecomment-618072318 - anyone have any relevant experience with that happening?
related thoughts from @drathier https://twitter.com/rtfeldman/status/1719694899681870183
For some recent work I have been reading the Ruby codebase a lot. It's written in C. They mostly use tabs but there are also spaces in there. So it's hard to read unless you have the right setting in your editor... which defeats the main point of using tabs in the first place.
So I think if we allow tabs there should be some way of preventing them from being mixed, at least for start-of-line indentation.
By the way, the best setting for the Ruby codebase is 6 spaces per tab, because of course it is.
yeah I think a reasonable design would be:
I'm kinda surprised not to see more advocacy for spaces haha
When I started using Roc I assumed the decision to use spaces had already been made and was a little disappointed because Roc seemed very modern in other ways.
I sometimes use a non-monospaced font for code, and one of the annoying things about it is the space character is very narrow, so using tabs would let me adjust the indentation in my editor.
My best arguments for spaces, in order of most to least important
The first point is pretty compelling to me personally. Otherwise I don't really care, either is fine.
I've never been exposed to the tab vs spaces argument before, so probably not super qualified to drop my 2cents in here. But from a quick read through some of the reddit threads and blogs link in the content above, I'm pretty convinced tabs seems like the right way to go. The biggest benefit I think is the accessibility argument, followed by the consistency between tooling.
If you want to really push for full tab support, and make sure the formatter rules are flexible (which I strongly suggest you do!), this editor setup should work fine:
I used this as my everyday setup when writing go and go fmt handles this wonderfully. I know it sounds crazy but it works really really well :)
If we go for a hard constraint where one thing is right and the other wrong, I wouldn't mind. But I can also totally imagine myself as a novice trying to pick up their first or second language and not understanding whitespace rules, spending way too long writing my first precious script, only to get a error because I used the wrong convention and not knowing that it's easy to fix with an automated tool. If we decide on something that can error, we'd want to pair it with immediately actionable advice on how to fix it and keep it fixed.
Yeah, accessibility argument wins. I'm sure most people don't actually care that much(even if it's fun to argue 1 way or the other), but for the people it does affect, it's probably way nicer to deal with.
I remember my first time writing a makefile having configured my editor to always convert tabs to spaces and spending waaay too long trying to fix it
I know Roc always tries to have helpful error messages, so I don't expect that to be a problem. :+1:
I think that ties into a broader conversation about first time user experience for various audiences. It's way way too early to lock anything down regarding that, but it's obviously worth keeping in mind early. Maybe it was my weird programming education in a physics degree, but I remember needing to learn C and C++ as someone who'd only done a little python, and the number of steps to get that working was very intimidating. The problem wasn't language syntax or deeper language concepts, it was all the weird stuff you needed to do to get it working on windows, the magic boilerplate code, etc.
So yeah, point being that accessibility is a lot more than the language features themselves; a lot of the coding infrastructure out there is pretty damn hostile to learn unless you've just picked it up or had a very conventional programming education. Roc is far ahead in most ways though, and I love how actively it's been prioritised.
Declan Joseph Maguire said:
If we go for a hard constraint where one thing is right and the other wrong, I wouldn't mind. But I can also totally imagine myself as a novice trying to pick up their first or second language and not understanding whitespace rules, spending way too long writing my first precious script, only to get a error because I used the wrong convention and not knowing that it's easy to fix with an automated tool. If we decide on something that can error, we'd want to pair it with immediately actionable advice on how to fix it and keep it fixed.
this is a great point - if someone new to the language has their editor configured to convert tabs to spaces by default, e.g.
Elias Mulhall said:
My editor is configured to convert all tabs to spaces
(and that's also the case with my editor personally)
I can imagine a beginner trying Hello World in the tutorial and getting this:
── SPACES USED FOR INDENTATION ──────────────────── hello.roc ─
This line is using spaces for indentation instead of tabs:
7│ main =
8│ Stdout.line "Hello, World!"
^^^^
Indentation is significant in Roc, and only tabs can be
used to indent. Make sure each indented line begins only
with tabs, and not spaces!
Tip: If your editor automatically converts tabs to spaces,
make sure it's configured not to do this for .roc files.
───────────────────────────────────────────────────────────────
is that an ok beginner experience? :thinking:
count me as a strong advocate for spaces over tabs. the only language i use with tabs is go. the theoretical benefits of user configurable visual spacing is far outweighed by the strangeness budget spent by being different from basically every other modern language.
also perhaps ironically i'm begging you all for 2 spaces, not 4
i'm also in the "tabs become spaces in vim" camp, so i special case go
I think as well as a compiler error, the editor extension/plugin should be able to give specific advice on how to configure Roc files to use tabs.
Maybe my knowledge about this is out of date, but if Roc is going to have its own editor that we want people to use instead of VSCode/Vim/Intellij/etc then the pros/cons of tabs vs spaces only matters when the code is being viewed elsewhere like github? Within the editor we could display the code with however much spacing the user wants regardless of if the actual saved file is using tabs or spaces?
Jacob said:
Yeah, accessibility argument wins. I'm sure most people don't actually care that much(even if it's fun to argue 1 way or the other), but for the people it does affect, it's probably way nicer to deal with.
accessibility is a big deal to me, but I've had a really hard time trying to figure out what the impact would be in practice here.
I've seen it said in many places that "configurable tabs is important for people with certain visual impairments" but then when I try to understand more deeply which visual impairments it would help with, how it would help them, etc. - it seems to come down to:
not knowing what the actual impact would be makes it hard to weigh the accessibility benefit here. Like screen readers are obviously a huge benefit to people who can't read text, so making things work well with screen readers is a huge deal. Specifically how big of a benefit are we talking about with tab widths? It's surprisingly hard to determine!
drew said:
count me as a strong advocate for spaces over tabs. the only language i use with tabs is go. the theoretical benefits of user configurable visual spacing is far outweighed by the strangeness budget spent by being different from basically every other modern language.
this is a fair point, although the same argument can be made for the status quo; Zig bans hard tabs (like Roc does today), and if you search for "zig tabs" you'll find a number of discussions where beginners were vocally unpleasantly surprised to discover the hard way that Zig doesn't allow hard tabs. To them, disallowing tabs is taking things out of the strangeness budget.
here's some food for thought:
has any language having the parser accept either tabs or spaces for indentation, but only on a per-file basis? e.g. if a file uses all spaces for indentation, that's fine, but if one line uses tabs that line is an error. (The parser could count how many lines had been indented one way vs the other, and give an error at the end of the file for any lines that were not the majority indentation character used. This might sound complicated but actually sounds very easy to implement to me.)
then of course the formatter would always choose one or the other (let's assume tabs) - but this design would mean that beginners are never tripped up by this in hello world, even if they haven't set up the formatter yet
also would mean if markdown files use spaces instead of tabs for code snippets, it's not a problem - but might be a problem if people copy/paste from those into their code base that uses tabs (although the formatter would fix that, and if they aren't using the formatter, they'd get an error anyway for mixing tabs and spaces for indentation in the same file)
has any language having the parser accept either tabs or spaces for indentation, but only on a per-file basis?
I don't think per file is the issue. It is just the inconsistency in general. My editor generates spaces for python. I can't visually see the difference between spaces and tabs. I edit a file with tabs and totally break it.
Imagine if a library you use does tabs, but your own project does space. Anytime you go to definition for a file in the library and edit it, you will break things due to tabs and spaces. Like your editor would have to be configured to detect the correct indent character per file. That sounds painful. Like you can add local overrides, but that is just worse than forcing only one.
Brendan Hansknecht said:
has any language having the parser accept either tabs or spaces for indentation, but only on a per-file basis?
I don't think per file is the issue. It is just the inconsistency in general. My editor generates spaces for python. I can't visually see the difference between spaces and tabs. I edit a file with tabs and totally break it.
ah interesting, so if everyone culturally used a code formatter, there wouldn't be a problem?
(a code formatter with no configuration options, like roc format)
I have one anecdote about astigmatism
Astigmatism can happen at any angle. For me, I essentially have the diagonal text shadow effect on all the time. Someone could have astigamatism that goes directly horizontal. This would make tab/space width harder to verify perfectly. That said, it would also lead to overlapping characters if it was quite bad. That would be totally unreadable. I would assume that most likely readability of words and requirement for glasses will come much before tab width being a problem.
interesting! Do you know of anyone who has a horizontal astigmatism who customizes tab width because of it? (And if so in which direction - making it higher or lower?)
I don't know of anyone.
Just thinking of how it could theoretically happen.
like one reason I care about the specifics here is that it might be the case that 4-space indent (for example) is already sufficient that in practice that's about what anyone who had that issue would choose to set the tab width at anyway, and being able to set it higher or lower wouldn't make a significant difference for them anyway
as with any user research, talking to people who are directly affected tends to reveal things that are different from what we predict their experience would be in theory :big_smile:
If 4 space indents are hard to see due to astigmatism, I am pretty sure that would mean all characters are stretching to be about 2 characters wide. So the text would be totally unreadable anyway. Though maybe I am missing something in how the duplication and stretch effect works for some people.
yeah that's exactly the type of thing that makes me crave specifics - e.g. in general if something is sufficiently serious, no amount of tweaks will make it legible and the answer is some other way of accessing the text (e.g. screen reader, refreshable braille display, etc.) - at which point tab width is not actually a benefit to that person because they aren't using a screen display at all
as an aside, I've read that modern screen readers in editors will generally condense repeated space characters (e.g. instead of saying "space space space space" they'll say "4 spaces" or "8 spaces" etc.) so I don't think there's a big difference between spaces and tabs in terms of verbosity
Oh, one extra note for:
ah interesting, so if everyone culturally used a code formatter, there wouldn't be a problem?
A code formatter would fix the issue if it is smart enough to deal with tabs and spaces on the same line while figuring out correct indentation levels. Cause I may edit someone else code by adding a new conditional. As such, I would be tabbing in their code father which could lead to mixed spaces and tabs depending on the editor config. Though I would just set my editor to match the formatter in practice, so this hopefully wouldn't come up as a real issue.
yeah I think that situation is similar to "I'm consistently using the same character for indentation, but I pasted some code in at the wrong indentation level" - can the code formatter guess what you meant and correct it?
and I think the answer is that often it can but of course not always
for example, if it encounters a when branch that would make sense here (e.g. there's an open when in progress) but it's at the wrong indentation level, we can safely assume it should just be indented properly and move on
I suspect the same is true of nested defs, e.g.
foo =
x + 1
bar = y + 1
baz = z + 1
this is technically a syntax error of bar doesn't have a closing expression, but from context clues we can guess that it's probably an indentation mistake and bar = should be at the same indentation level as foo =
Throwing in my vote: I'd lean towards tabs because tabs are semantic. Using spaces for vertical alignment (aside from indentation) is a bad practice in general (aside from special cases like hard coding a big list of tabular data). At least at the beginning of a line, Roc code should be indented exactly one tab-width more than the line above, which tabs are better at than spaces. I do personally prefer spaces but only cuz I'm used to them, and switching to a new language is the right time to change that.
I also think that the compiler should be as forgiving as possible. Maybe a compiler error if bad indenting means the compiler can't figure out the semantics, a warning if there's mixed whitespace within one file but the compiler can figure it out, and silently succeeding if a file is consistently spaces. This is a formatting concern, so only the formatter should be the enforcer. That way people could try the language with spaces, and only run into this issue once they call roc format and show they want to conform to the standard.
Richard Feldman said:
ah interesting, so if everyone culturally used a code formatter, there wouldn't be a problem?
We wouldn't be able to rely on that for the new user Hello World experience
I was more thinking that tab being 1 character rather than space for braille displays (maybe screen readers too?) might be easier. I wasn't really thinking about the adjustable tab width part.
yeah I'd love to learn more about braille displays, but so far the most detail I've been able to find is "they exist, and it's conceivable that some programmers might use them for programming instead of screen readers, but also maybe not" which is not much to go on :sweat_smile:
Yeah, I remember seeing a blind programmer in college, but pretty sure he just used a screenreader and a normal keyboard.
I live with a blind programmer, and he uses screenreaders as they're functionally mandatory for navigating computers. Then again, he was blinded as an adult.
@Declan Joseph Maguire do you know if he happens to know anyone who uses a braille reader?
I'd love to learn more!
If it does not conflict with the indentation rules of roc, I would vote for the parser allowing any mix of tabs and spaces. This will solve any problem with
The formatter of cause has to choose one. Since the purpose of tabs is to do indention, they are more configurable, and are only 1 byte, I would vote for tabs. But having a formatter doing it for me is more important than the actual indentation style.
Also interesting, but I'm not sure how relevant: elastic tabstops (VS code extension)
Accepting any mix does not magically fix the issue. I have had plenty of python code where it worked upon copy but would break whenever I edited the file. Really painful and annoying to work with.
Especially painful because tabs and spaces look the same. So I would have no visual way to even see where or why the code is broken
I honestly much prefer only accepting one and erroring out on the other.
I am fine with the formatter accepting both, but I don't thing roc run or roc bulld should accept both.
They should just error and say that the user can try running roc fmt or manually converting all tabs to spaces (or spaces to tabs, whichever we pick)
Fabian Schmalzried said:
Also interesting, but I'm not sure how relevant: elastic tabstops (VS code extension)
I don't think that would work on a whitespace significant language like roc or Python.
Though really interesting idea
My little suggestion, pick one and make everyone follow because consistency trumps all.
Have the compiler work but emit a warning. I totally agree with @Sky Rose, it's a formatting concern, formatting is worth taking an official stance on, but if you want to do something visually yuck or you are writing your first 10 lines of rust in vi then it should still just work.
Make your formatter fix it if it's wrong.
If you are worried about the beginner experience, have a warning that both explains that you should change the setting that either inserts tabs or spaces, tells you to run "roc fmt" to fix it right now and links to a page explaining why it is this way and a little explanation for how to fix this in each major editor.
As an editor extension, in many cases you can set settings like whether to use tabs or spaces in your language, so assuming a beginner is on the "golden path " it should just work.
Lasty i think you should choose tabs, because we shouldn't live in a world of fixed indentation. When I'm on my best game and i want to absorb as much code as possible I'm generally in a 2 space indentation mood, but when it's 2am and I'm staring at my tiny laptop with blurry eyes 4+ spaces of indentation is the only hope i have of discerning one indentation level from another. The option to change your indention whenever the mood strikes is an ultimate freedom we all deserve and feel the loss of, even those too oppressed by space tyranny to realize that. ;)
The option to change your indention whenever the mood strikes is an ultimate freedom we all deserve and feel the loss of, even those too oppressed by space tyranny to realize that
The funny part is that many editor now can render spaces at any width. So they have a way to get what you are talking about despite using an exact number of spaces. It's an interesting work around that has been implemented many times.
Last updated: Jun 16 2026 at 16:19 UTC