Do you use formatter in your elixir project?

Elixir’s formatter is specifically designed to not allow that, which yes is irritating, but I’ve worked around it by putting some things in strings and then just extracting it at compile-time, a bit wtfery when someone looks at the code but it’s better than my finely crafted math tables getting screwed up, lol.

Entirely agree with you!

3 Likes

The formatter downsides that people have pointed out are real but are far outweighed by the benefit of consistent formatting. Consistent both across your project and from project to project. We all have our preferences on style, but you get used to anything after a while and the consistency is a joy.

On my project, I always ensure that one of my pipeline stages runs the following command:

mix format --check-formatted

This returns a non-zero error code if the formatter would have to change anything to make the code formatted, which keeps our codebase consistent. Team members are then responsible for ensuring that formatting happens as part of their workflow (mostly through format on save in VS Code, but in some cases pre-commit hook, or just remembering).

3 Likes

I’ll also second that if you are going to use the formatter, you should add it to your editor so that you can see what it does on save. That way you can improve its output and ensure your code is still readable. Its not really designed to make code readable by default. Its just enforcing some pretty rough rules and what it generates can be janky if you don’t work on correcting it. Said differently, if your going to use the formatter, running mix format should be considered the first step in formatting your code. Not the last.

Finally, while people talk about consistency, I just need to say that you aren’t a bad person for choosing to not use the formatter, simply because it doesn’t suit your style or output the code in a way that is most readable to you and your team. If your running an open source project you can help signal this to other folks by updating your .formatter.exs file to include an empty list for inputs: []. That way files won’t get churned.

8 Likes

Yeah, Elixir’s formatter can be stricter. For example, if I exceed my line limit (I set it to 95) then the formatter correctly splits the line in two. But if I then change my mind and rename some variables to shorter names, on save the formatter doesn’t collapse those two lines back into one. Which it really should.

Contrast this with Rust’s formatter which is absolutely brutal and will not only reformat your code but also remove things it deems unnecessary, e.g. a single statement in a pattern matching arm that you used curly braces around? Yeah, the formatter removes them because again, it’s a single statement and it’s acceptable for the compiler, and it’s also more terse.

So I’d even venture saying that Elixir’s formatter doesn’t go far enough. I’d love it if it was even more opinionated!

2 Likes

Fully agree. Another example:

case number do
  1 -> :one
  2 -> :two
  3 -> :three
  number -> :very_big
end

add an inspect:

case number do
  1 -> :one
  2 -> :two
  3 -> :three
  number ->
    IO.inspect(number)
    :very_big
end

formatter:

case number do
  1 ->
    :one

  2 ->
    :two

  3 ->
    :three

  number ->
    IO.inspect(number)
    :very_big
end

thats ok, but its not changed back when the inspect is removed.

5 Likes

I personally like using the formatter and I have set up to format on file save. I like that I can write whatever, not caring about spacing etc, and the formatter would do roughly what I’d expect.

I don’t mind at all when other people choose not to use it, it’s their code after all!

I have a small wrapper over mix, m, and m format [1] (which my editor would execute on file save) would skip formatting based on simple heuristics.

[1] dotfiles/m at 66cb3c9ff201c26a9173b70d17055ee0711ce9ce · wojtekmach/dotfiles · GitHub

4 Likes

I’m mostly working on a project that’s (to me) ‘legacy code’ and it’s formatted somewhat inconsistently.

But I think some of my own idiosyncratic preferences are pretty useful (or at least pretty) and formatting code in my own style seems helpful for reading and understanding code as well as being enjoyable to read thereafter.

I didn’t know “tabular code” is a thing (with a name), but that’s a big part of my personal style, in any language. I find it so much more readable than alternatives; so much faster and easier to scan, compare, and even edit.

But I have had some limited use from using the default formatter, mostly just for individual files that have ‘archaic’ formatting. It’s a really helpful base formatting and matches my own preferred style pretty well as-is.

2 Likes

How I would love Elixir to not touch ‘with’ statements (or apply tabular formatting!) They allow such readable code…until the formatter kicks in and makes the flow hard to follow :frowning:

It’s probably my only beef with it.

3 Likes

I don’t like formatter at all. I can understand, that the code is more consistency, so everybody can “read” it. On the other hand, I like to have my own style (tabular code). After all, I am the author of the code and you can see that there. I write this code and have been doing so since 1984, before anyone formatted the code. So when I program, I want to write good code that works effectively and whose logical relationships can be read in the program sequence. With comments in the places that are important (the elixir formatter moves my comments, arrg!).

I started on one project and didn’t call “mix format” on commit, then I was told by four other developers to call “mix format” even when there were already three such comments to read. In the end, everything was nicely formatted, but the application totally failed. And none of these developers was able to solve the problems of the application, although now with the formatted code all developers can read the code so easily :slight_smile:

In other words, mix format does not help to write good code.

Nobody is claiming that it does. It’s a measure for team-wide consistency, nothing more.

2 Likes

In other words, mix format does not help to write good code.

Depends on what you are meaning by “good code”. If you write alone, nobody sees your code, so yeah, it won’t help to write better code. Nobody will get advantages from the systematization. But if other people read and try to understand your code, familiar syntax will help a lot. And it is worth nothing to say, that to understand another person code is much harder than your own, so in my opinion EVERYONE SHOULD TRY TO HELP TO DO THAT in any way it’s possible. As i said earlier, as longer i use it, as much more i like it. And for me formatter main goal is not to write good code for my self(it helps widely though), but for other people to do common work easy, not only my own.

2 Likes

I am really struggling to understand what you mean with this. I mean, did it break because of the placement of the comments? Or did you remove the comments because the formatter didn’t want you to put them there?

Either way though, I’m one of those that think a codebase full of comments normally is a code smell. And well, I say normally because I know there are places we totally need to leave comments, and depending on the complexity of application you’re writing, this might happen more often.

Anyway, I really try to write the code in a clear way that makes it obvious to other people what it should be doing, so no comment is needed. When that’s not possible, then I extract functions for the parts that need more explanation and write comments as if they were an @doc, which doesn’t get rearranged by the formatter.

So in the end, again, you just kinda adapt your code, to find a way that the formatter accepts and it’s pleasing for you. It might not be perfect for you, but when there are multiple people, you have to play the good citizen because maybe what’s perfect for you might not be perfect for them, so you have to both meet in the middle, and the formatter is a good way to do that IMO.

3 Likes

How do you do it, working as a team on one code-base without a formatter? Does nobody use a formatter and all try to follow your style by hand? Do some use a formatter, some don’t? Both are very tedious and you’ll end up with loads of useless diffs in source control. You can use different styles in a project without messing up source control, but you need a configurable formatter (like clang-format) and some hooks to always push a common style and pull a custom style. There is no configurable formatter for Elixir.

3 Likes

Yes, apart from all the reasons mentioned here, I and my team use the same code formatters so that we don’t face unnecessary formatting code changes and challenges while code review.

1 Like

You can get around formatter-code-changes with a configurable formatter and hooks (as mentioned above) .
But you still need to learn to read code in another style if you are reviewing or pair-programming (or just plain old staring at the same screen looking for a bug).

2 Likes

we have similar:

"dev.checks": [
        "format",
        "compile --warnings-as-errors --all-warnings",
        "credo --strict --only warning --ignore Consistency",
        "dialyzer"
      ]

we do ci/cd checks for every PR:
CleanShot 2021-05-17 at 12.52.54
and we do not allow to merge PR which is not formatted.
First of all is readability for all developers. It means:

  • the code readability,
  • diff changes in PRs/commits.

I think all of us already saw commit from another dev where was applied different code formatting than was before with 1000 changed files and 10_000 new spaces/tabs/enters :smiley:

I think all of our developers use VS Code and auto formatter after save. We use default js/css formatter in IDE but we are thinking to use specific one to have cleaner changes but we don’t do a lot of changes in those files.

2 Likes

I use prettier for both JS and JSON and I like the result.

And yep, this is how I setup CI/CD myself.

2 Likes

I agree, I significantly prefer Rust’s formatter over elixir’s as well (and not just because it puts trailing comma’s on multi-line constructs, which it does do, lol), but it just seems overall ‘smarter’ and significantly more opinionated about things. Like with the example by @Sebb above with:

case number do
  1 -> :one
  2 -> :two
  3 -> :three
  number ->
    IO.inspect(number)
    :very_big
end

And Elixir’s formatter blows it up into that huge many-line annoyance, compare to how rust handles the same construct (I added an extra block on two just to show it removes it):

match number {
  1 => "one",
  2 => {"two"}
  3 => "three",
  number => {
    dbg!(number);
    "very_big"
  }
}

The cargo fmt will change it to:

    match number {
        1 => "one",
        2 => "two",
        3 => "three",
        number => {
            dbg!(number);
            "very_big"
        }
    }

It doesn’t matter how many lines things are, what format things are in, etc… etc… etc… The formatter literally just parses it into the Rust AST and then outputs it again. You can override things with #[...] calls like disallowing formatting on a section for example as well, but honestly I’ve used that like once, it’s just really really good at formatting. Even in the config file the only change I made was to use tabs instead of spaces because screw 4 spaces being so crazy wide. ^.^;

And yes, if you remove the dbg line it will format back in to:

    match number {
        1 => "one",
        2 => "two",
        3 => "three",
        number => "very_big",
    }

Yeah this is one of the worst things the elixir formatter does, and it’s not really its fault, but rather because I still to this day think that with’s syntax was very mis-chosen (same with for too). I had a better form of with before with existed as a macro, but the syntax formatting it used was broken by elixir in a backwards incompatible syntax update (around 1.6 or 1.7 or something, and by backwards incompatible I mean it was a form that macro’s took before, then the compiler errored on after the update, so yes, the very definition of backwards incompatible)… :frowning:

This is something annoying about the formatter as well, it doesn’t really ‘attach’ comments to the AST it builds very well, though I got used to how it does it.

2 Likes

I’ve started using it, set up a hook on emacs to format on save, even on personal projects

And can say I got used to figure out if I typed something wrong with this feedback too.

On the other hand though, it sometimes really messes up what I think would be a good layout (multiline function heads get a bit too much indenting), -> sometimes get broken into two lines where I would prefer not to, comments get moved around (and this one is a bit more annoying, sometimes you just want to clarify a clause in a case or something). I would also like to have tabular organisation on with but it’s not something that happens a lot of times. Overall though, I think it’s better to have a consistent styling even if not what I would always do - perhaps some things can be “improved” though (for lack of a better word).

2 Likes

That’s great!