Crowdhailer

Crowdhailer

Creator of Raxx

I’ve been hearing much about the new formatter and it’s something I have been keen to try.
I find examples buy far the most illuminating way to try some new tech. To that end I though I would blindly run the new formatter on my largest open source Elixir code base, Ace.

I did no preparation before hand and in one swoop was able to format the whole project using

$ mix format mix.exs "lib/**/*.{ex,exs}" "test/**/*.{ex,exs}"

The full change commit

Results

  • My project is now larger. 1369 lines added but only 752 removed.
    A lot of these are empty lines. Every case clause is separated by a new line and so is every function head.
    It looks like my personal convention of separating different functions but not different function heads of one function is now over
  • Brackets are now applied automatically so no more dealing with those warnings. This is a big win.
  • Numbers lose underscores 65_53565535 :frowning:
  • Several cases where things are now indented to line up with something above rather than just two spaces, this is probably what I am least happy about but I can get over it for the consistency
  • Comments now always end up on a separate line.

In conclusion I think that is a great additions and I hope that the numbers will eventually be formatted with the underscores

Showing Posts 150 to 141

jozef

jozef

You can always use

alias Foo.Api.Google, as: ApiGoogle
alias Foo.Authentication.Google, as: AuthenticationGoogle
OvermindDL1

OvermindDL1

For anyone curious, it’s fixed in master. :slight_smile:

sasajuric

sasajuric

Author of Elixir In Action

EDIT: José confirmed on IRC that the behaviour I’ve reported in this post is a bug, so I created the issue on Github.

I’ve noticed some weird formatter behaviour in Elixir 1.6.4, which I personally don’t like. I’m not sure if it’s a feature or a bug, so I’m reporting it here.

From what I can tell, the formatter seems to respect my vertical choice of function parameters. So both of the following are fine:

Enum.reduce(foo, bar, baz)

Enum.reduce(
  foo,
  bar,
  baz
)

This is cool, because in some cases, I like to break each param on a separate line, even if the line itself is not long.

Now, if the last param is a lambda, the formatter doesn’t respect the vertical choice. In other words, if I start with this code:

Enum.reduce(
  foo, 
  bar, 
  fn el, acc -> baz(el, acc) end
)

It’s always turned into

Enum.reduce(foo, bar, fn el, acc -> baz(el, acc) end)

That becomes somewhat annoying when the lambda is multiline, because my code is always force formatted into

Enum.reduce(foo, bar, fn el, acc ->
  baz(el)
  qux(acc)
end)

Personally, I have problems when reading this layout, because the lambda arguments are further right than the body.

This becomes particularly annoying in the following case:

Enum.reduce(
  moderately_complex_expression, 
  moderately_complex_expression, 
  fn element, accumulator ->
    do_something(element)
    do_something(accumulator)
  end
)

The code gets reformatted into:

Enum.reduce(moderately_complex_expression, moderately_complex_expression, fn element,
                                                                             accumulator ->
  do_something(element)
  do_something(accumulator)
end)

Which I find quite terrible to read.

Of course, the code can be improved by using temp local vars and/or named functions, but in some cases I just prefer to inline everything. Sadly, given the formatted code above, inlining is not an option anymore.

So my question would be: is such formatting intended or is this a bug?

cc @josevalim

scarfacedeb

scarfacedeb

What’s the consensus on grouping multiline functions with the new formatter?

I know that it still allows to group one-line functions, but it’s no longer possible to apply the same styling to the longer functions.

I noticed that it was a quite common way to format the code, e.g. hex.pm grouped multiline functions not long ago:
https://github.com/hexpm/hexpm/blob/c8d753f811ce7ecf20b1110fbe8d2185655e50ec/lib/hexpm/accounts/audit_log.ex#L12

But now it was run through new formatter, and I think that it looks worse (notice haphazard new lines around extract_params):
https://github.com/hexpm/hexpm/blob/master/lib/hexpm/accounts/audit_log.ex#L61

I’m aware that the formatter doesn’t know what’s a function, and therefore cannot make an intelligent decision here. But does it mean that the official position is against the old style of grouping and you aren’t planning to bring that ability back? :pensive:

OvermindDL1

OvermindDL1

Yep it bugs me too, it’s because with is a multi-arity function call (ack! Those should be banned from elixir!), however you can kind of ‘work around’ it by surrounding the with ‘arguments’ with parenthesis (which is what I do now since the formatter broke my previous with\ syntax form), like:

  def new(type, %Coord{} = origin) when type in @types do
    with(
      %MapSet{} = coords <- coords(@offsets[type], origin),
      do: {:ok, %Island{type: type, coords: coords, hits: MapSet.new()}},
      else: ({:error, _reason} -> {:error, :invalid_island_args})
    )
  end
rayex

rayex

Hi,

I like the new code formatter. I just noticed an inconsistency though between the with and if formats:

  def new(type, %Coord{} = origin) when type in @types do
    with %MapSet{} = coords <- coords(@offsets[type], origin),
         do: {:ok, %Island{type: type, coords: coords, hits: MapSet.new()}},
         else: ({:error, _reason} -> {:error, :invalid_island_args})
  end
  def guess(%Island{} = island, %Coord{} = guess) do
    if MapSet.member?(island.coords, guess),
      do: {:hit, update_in(island.hits, &MapSet.put(&1, guess))},
      else: :miss
  end

As you can see above, the do: and else: clauses are more indented for with than for if.
And I understand why but it just struck me.

Thanks

josevalim

josevalim

Creator of Elixir
kelvinst

kelvinst

I had the same problem, but my solution was a little bit different:

[
  inputs: [
    "mix.exs",
    "apps/*/{config,lib,test,priv}/**/*.{ex,exs}",
    "config/**/*.{ex,exs}"
  ]
]

:wink:

RomanKotov

RomanKotov

Thank you for great formatting tool. I’ve found it very helpful.

After generating new umbrella project I started adding .formatter.exs file with the following contents:

[
  inputs: ["mix.exs", "{apps,config}/**/*.{ex,exs}"],
]

But mix format failed to format some files

mix format failed for file: apps/app_web/assets/node_modules/phoenix/priv/templates/phx.gen.schema/schema.ex
** (SyntaxError) apps/app_web/assets/node_modules/phoenix/priv/templates/phx.gen.schema/schema.ex:1: syntax error before: '='
    (elixir) lib/code.ex:442: Code.format_string!/2
    (mix) lib/mix/tasks/format.ex:293: Mix.Tasks.Format.format_file/3
    (elixir) lib/task/supervised.ex:88: Task.Supervised.do_apply/2
    (elixir) lib/task/supervised.ex:38: Task.Supervised.reply/5
    (stdlib) proc_lib.erl:247: :proc_lib.init_p_do_apply/3

This error is due the file with .ex extension contains some string interpolations, like defmodule <%= inspect schema.module %> do. This fact is not a problem, because entire node_modules dir is in .gitignore, so .formatter.exs inputs must skip formatting this file. I would like to share my solution of this problem, because I think someone else could find it helpful.

Now my basic .formatter.exs file looks like:

inputs = "git ls-files | grep -E \"*\\.exs?$\""
         |> String.to_charlist()
         |> :os.cmd()
         |> to_string()
         |> String.split(~r{(\r\n\|\r|\n)}, trim: true)

[
  inputs: inputs,
]

So it formats elixir files only under the version source root.

Deithrian

Deithrian

Yeah, I’m not gonna be using it, since these are not bugs.
I just don’t understand why you guys committed to having parentheses, but then remove them from if statements, then completely ignore why they exist in the first place, by placing closing ones on new lines, and then double the lines of code with new line for everything, not to mention what the formatter does with code that uses long, descriptive names.
My code looks like a Tasmanian devil went and had its way with every line. :joy:
I’ll pray that it doesn’t get adopted :blush:

Where Next? Top

Trending in Discussions Top

AstonJ
As the title says, please share what you’ve been up to with Elixir. Whether that’s been learning it, looking into it, making stuff with i...
2977 94592 917
New
cblavier
Hey there, It’s been more than a year since we started using LiveView as our main UI library and building a whole library of UI componen...
New
mudasobwa
I am happy to introduce the very α version of the new programming language compiled to BEAM. Welcome Cure. It has literally three kille...
New
heathen
Quite interesting article Google brought me. Didn’t find any mentions about it here. What do you think in general? Would you use togethe...
New
mhanberg
Hi everyone! The first release candidate for the Expert language server project is now available! We’ve published a press release detai...
New
AstonJ
Since we have deprecated our Erlang sections (as we have dedicated Erlang Forums now) let’s add this thread for those who’d like to post ...
New
maennchen
:warning: Security advisory: Decimal DoS vulnerability A vulnerability has been published for decimal where very large exponents can cau...
New

Other Trending Topics Top

JesseHerrick
Hey, I’m Jesse and I’m the main contributor behind Dexter, a full-featured, lightning-fast Elixir LSP optimized for large codebases. It s...
New
marciok
Hi there! We created Gust: A task orchestrator inspired by Airflow. For those who have never heard about Aiflow, it’s a Python-based wor...
New
jimsynz
Beam Bots (or just BB for short) is a framework for building fault-tolerant robotics applications in Elixir using familiar OTP patterns. ...
New
Dmk
Xamal is a deployment tool for Elixir apps that deploys native releases to bare metal servers over SSH. It’s a port of GitHub - basecamp/...
New
netoum
Corex is an accessible, unstyled UI component library for Phoenix that integrates Zag.js state machines using Vanilla JavaScript and Live...
New
webofbits
With AI doing more of the implementation work, I’ve been wondering how much coding I should deliberately keep doing myself. My main conc...
#ai
New

We're in Beta

About us Mission Statement

Options

Thread Display Mode




Thread Preview

Skip Thread Previews