bmitc
Having trouble with `formatter` and `case`
Hello! I am having issues with the Elixir formatter and a long case expression. What’s happening is that this:
defmodule Test do
def evaluate_contract(%{from: from, to: to, value: value} = t, contract) do
case contract do
x when is_number(x) -> x
s when is_binary(s) -> s
[] -> true
{} -> true
true -> true
false -> false
{:if, co, tr, fa} -> if evaluate_contract(t, co), do: evaluate_contract(t, tr), else: evaluate_contract(t, fa)
{:+, left, right} -> evaluate_contract(t, left) + evaluate_contract(t, right)
{:*, left, right} -> evaluate_contract(t, left) * evaluate_contract(t, right)
{:-, left, right} -> evaluate_contract(t, left) - evaluate_contract(t, right)
{:==, left, right} -> evaluate_contract(t, left) == evaluate_contract(t, right)
{:>, left, right} -> evaluate_contract(t, left) > evaluate_contract(t, right)
{:<, left, right} -> evaluate_contract(t, left) < evaluate_contract(t, right)
{:and, left, right} -> evaluate_contract(t, left) and evaluate_contract(t, right)
{:or, left, right} -> evaluate_contract(t, left) or evaluate_contract(t, right)
:from -> from
:to -> to
:value -> value
_ -> false
end
end
end
gets formatted to:
defmodule Test do
def evaluate_contract(%{from: from, to: to, value: value} = t, contract) do
case contract do
x when is_number(x) ->
x
s when is_binary(s) ->
s
[] ->
true
{} ->
true
true ->
true
false ->
false
{:if, co, tr, fa} ->
if evaluate_contract(t, co), do: evaluate_contract(t, tr), else: evaluate_contract(t, fa)
{:+, left, right} ->
evaluate_contract(t, left) + evaluate_contract(t, right)
{:*, left, right} ->
evaluate_contract(t, left) * evaluate_contract(t, right)
{:-, left, right} ->
evaluate_contract(t, left) - evaluate_contract(t, right)
{:==, left, right} ->
evaluate_contract(t, left) == evaluate_contract(t, right)
{:>, left, right} ->
evaluate_contract(t, left) > evaluate_contract(t, right)
{:<, left, right} ->
evaluate_contract(t, left) < evaluate_contract(t, right)
{:and, left, right} ->
evaluate_contract(t, left) and evaluate_contract(t, right)
{:or, left, right} ->
evaluate_contract(t, left) or evaluate_contract(t, right)
:from ->
from
:to ->
to
:value ->
value
_ ->
false
end
end
end
You can try this with the online formatter. I think this is a pretty drastic format and greatly reduces the function’s readability. It also triples the case expression’s body.
I expected the if expression to get expanded to multiple lines but not have every other case expanded to multiple lines. I think after expanding the if, the formatter could put spaces between the clauses (I wouldn’t), but I don’t see the reason why it puts all the short match results on a new line just because of one long result expression.
Is this expected? If so, does anyone know how to configure or any existing custom plugins that work a little better for case? One option I have is to simply shorten the function name. Although not an ideal change due to formatting, that may be the easiest solution.
Most Liked
03juan
This is expected behaviour to keep formatting standard and predictable. If one clause is multi line all clauses are made multi line.
Breaking out the long lines into separate functions to keep the case clauses short is the right way. It’ll also make the code more understandable by using descriptive names.
bmitc
Yea, I am in one of the stages of “formatter grief” at the moment.
Although, I do wish there was some configuration for these opinionated stances for individual orgs, teams, or projects to settle on.
For now, I’m trying to move into the acceptance stage of formatter grief. I’m also building up so-called tricks that help me strike a balance between what I’d like vs what the formatter does. I’ll paste what I came up with tomorrow, and I think it’s a fine enough compromise.
I’ll take a look at the Elm docs you sent tomorrow. Thanks for those.
stefanchrobot
I think a better word here - and what @03juan actually had in mind - would be “consistency”. Granted, it’s consistency with it’s own rules which can be changed. But my take is that the fewer the rules the better.
Yes, this is the way. There are situations where no code formatter rules will make the code look good (“for most people
”) unless you refactor it. For me, your code is a good example of that. Shortening the function name is one of the approaches (you can have top level evaluate_contract and then eval). Refactoring the common parts would be another:
{op, left, right} when op in @binary_ops -> evaluate_binary_op(t, left, right, op)
I’d say this is all or nothing. You need to be quite opinionated when deciding which options should be configurable.
Popular in Questions
Other popular topics
Categories:
Sub Categories:
Forums
Popular Tags
- #ecto
- #liveview
- #troubleshooting
- #learning-elixir
- #deployment
- #library
- #erlang
- #testing
- #genserver
- #mix
- #absinthe
- #remote-other
- #otp
- #plug
- #how-to-question
- #macros
- #postgres
- #channels
- #elixirconf
- #exunit
- #discussion
- #code-sync
- #javascript
- #podcasts
- #onsite
- #dialyzer
- #docker
- #authentication
- #umbrella
- #full-time-contract
- #podcasts-by-brainlid
- #ecto-query
- #elixir-ls
- #phoenix_html
- #iex
- #blog-post
- #graphql
- #genstage
- #ai
- #websockets
- #supervisor
- #advent-of-code
- #elixirconf-us
- #distillery
- #processes
- #forms
- #api
- #metaprogramming
- #security
- #performance









