pmarreck

pmarreck

Mix formatter for tabs instead of spaces

Go, which I am a massive critic of, got 2 things correct, in my estimation.

The first is gofmt, which actually inspired mix format. But we didn’t borrow enough, it seems, because…

The second is preferring tabs instead of spaces. Why?

You’re going to read this, probably be convinced, but then say “well, it’s too late”. Or you’ll say “but the community”.

Well, guess what. The community is already using mix format. And since mix format is both configurable and has a plugin architecture, if you mix format any code you’ve copied with tabs, it will happily convert it right back to spaces (or whatever format that the plugins and configuration in your project specify). Which means that the only argument that can truly be made here is that whitespace indentation decisions should be made at the project level, not the language level. The fact that the compiler is whitespace-agnostic (because it would be pretty insane not to be… Unless you’re an official formatter, apparently) is proof of this.

To that end, here’s a mix format plugin to make tab indentation project-wide: An Elixir formatting module for `mix format` that converts leading spaces to tabs. · GitHub

So whether it’s 2 spaces per tab, 3 spaces per tab, 4 spaces per tab, 8 spaces per tab, or actually using tabs as they were originally designed since the compiler doesn’t care; vision-impaired people DO care, and the formatter will align it to your project’s requirements anyway… So let’s choose freedom here

Most Liked

hauleth

hauleth

That is not fully true, as foo:bar is not the same as foo: bar. Elixir is whitespace sensitive language (it just to not use off-side rule).

Tabs weren’t designed for indentation. Tabulation character was designed for tabular data (it is in the name). So some people say “tabs for indentation, spaces for alignment” this is explicitly against design purpose of tab, as tab was exactly for alignment purposes (that is also why tabs are elastic, so you can adjust the tab stop to match your table data).


But going back to the argument, while I agree that for some visually impaired people tabs have more sense than spaces I still prefer spaces over tabs, because tooling around tabs is enormous pain in the arse.

  1. You want to enforce the maximum line length? Good luck with doing that just in editor when there are elastic tab widths. You can enforce it with formatter, but for me it will be enormously irritating during work if I would use different TS than rest of the team, as it would constantly move stuff around.
  2. Online tooling is super inconsistent wrt to the support of the tab stops. GitHub only recently (2-3 years ago) gained support for custom tab stops and support for defining tabs stops in the project (via .editorconfig). Earlier it was defaulting to 8 and you either like it or you can GTFO. Other tools not always provide such flexibility.
  3. Support for multiple tabletops in single project is poor in case of CLI/TUI tools. You want to have different TS for Makefile (8), Rust (4), and Elixir (2) files? Good luck when you will fire git diff and you will have changes in different files.

Some may say, “well, we can fix these tools to allow that stuff”. Yes, we can, but at the same time we can fix these tools to

  • Support displaying leading spaces with different width than the rest of line
  • Add support to the editor to support braille reader in a way that will for example start line with <indentation width><space> to provide a way for the user to know how deeply indented they are without shifting through N characters (no matter what these are) or just simply display the leading spaces differently from other spaces (just like editor in general often do).

So yes, this is a problem, but saying that “spaces are the problem, and the only solution is to move to tabs” is the same as saying “you are the problem, fix yourself”.

10
Post #9
hst337

hst337

Finally, a topic worth a discussion.

sodapopcan

sodapopcan

I don’t disagree with any of these arguments. The braille one is especially compelling. I think there are a couple of things that make this awkward for Elixir, though.

One thing you can’t do with tabs, which the Elixir formatter makes use of, is line up code with odd/random spacing. Take with for example of how multi-head anonymous functions get lined up when reaching the line length. There’s no way for the formatter to do that in a way will reliably look nice across editor configurations.

The other thing is line length. With Elixir being a dynamic language it encourages full names for variables whereas I believe Go encourages single letter variables. When you start having longer variable names, larger indentations are going to make for very long lines. Maybe I’m not thinking through it well enough, but it would require the formatter to figure out how to collapse indentation that isn’t necessarily even (as per the first paragraph) in order to figure out if the line length is all right.

Accessibility concerns are very important but it’s just so hard to please everyone. Different editor tools can help—dimming code outside the current block or highlighting ends differently, for example. I don’t like saying “just rely on your editor” though it applies here since that’s the idea behind using tabs. Editors are also capable of retabbing when opening a file and converting back before saving, though that is far from ideal.

dimitarvp

dimitarvp

I am sympathetic to people with poor or no eyesight – I am at -6.75 dioptres of myopia myself.

It’s just that statistically it doesn’t make sense to inconvenience most of the people to cater to a smaller portion of people. Plus those with special needs already have specialized tools, as far as I am aware.

Bringing this to VScode, Emacs and [Neo]Vim will cause a huge stink.

Though realistically I don’t see a problem to just f.ex. make an Emacs or NeoVim function that changes tab width at the press of a keyboard shortcut either.

smathy

smathy

Yeah, noise for me too, but I also generally avoid deep nesting because it’s usually an indicator of some other smell.

I have to admit that with breakindent, breakat and showbreak I really don’t care about line width, although like nesting it’s definitely another indicator for smell.

Where Next?

Popular in Libraries Top

hpopp
After just over two years in development, this latest version of Pigeon is what I finally consider done in regards to my original vision ...
New
tompave
Hello there, I would like to share a feature toggles library (AKA feature flags) I’ve been working on. The main package is FunWithFlags...
New
sasajuric
I’d like to announce a small library called boundaries. This is an experimental project which explores the idea of enforcing boundaries ...
New
mbuhot
Leverage Open Api 3.0 (Swagger) to document, test, validate and explore your Plug and Phoenix APIs. Generate and serve a JSON Open API ...
New
michalmuskala
Hello everybody. I have just released Jason - a new JSON library. You might be wondering, why do we need a new library? The primary foc...
New
Jskalc
Hi! Today, after a couple weeks of development I’ve released v0.1 of LiveVue. It’s a seamless integration of Vue and Phoenix LiveView, i...
New
zorbash
I created Kitto a framework for dashboards inspired by Dashing. [demo] The distributed characteristics of Elixir and the low memory foo...
New
tmbb
PhoenixWS - Websockets over Phoenix Channels Source code on Github here: https://github.com/tmbb/phoenix_ws Phoenix channels are a great...
New
vic
Expat is a tiny experiment I did for extracting patterns and being able to reuse them (compose and share patterns between elixir librarie...
New
mischov
import Meeseeks.CSS html = HTTPoison.get!("https://news.ycombinator.com/").body for story &lt;- Meeseeks.all(html, css("tr.athing")) do...
New

Other popular topics Top

senggen
Erlang/OTP 25 [erts-13.2.2] [source] [64-bit] [smp:8:8] [ds:8:8:10] [async-threads:1] 15:22:35.803 [error] gen_event {lager_file_backend...
New
dotdotdotPaul
Okay, I'm having a heck of a time trying to figure out how to best handle the validation of belongs_to associations in Ecto. I'm sure I'...
New
JorisKok
I have a server on AWS, and was running a load test using artillery. When looking at the Phoenix dashboard I see the Ports going to 100% ...
New
axelson
This post is a wiki (feel free to hit the edit button near the bottom right of this post to add your own changes!) This post collects co...
239 45766 226
New
New
lastday4you
I wanted to check elixir version in phoenix because i found that my elixir is 1.5 but when i use Enum.chunk_by it said the function is un...
New
vac
Hi, I'm quite new in Elixir and I'm trying to format a string to a PEM format. I have the certificate value like MIIDBTCCAe2...... and ...
New
shahryarjb
Hello, I have map which I want to convert it to string like this: the map: %{last_name: "tavakkoli", name: "shahryar"} the string I ne...
New
beno
I will often find my self writing things similar to: case some_value do nil -&gt; something() "" -&gt; something() _ -&gt; someth...
New
skosch
To my knowledge, put_in, Map.update etc. all have the one limitation of not automatically creating intermediate keys when needed (for exa...
New

Sub Categories:

We're in Beta

About us Mission Statement