Stream: ideas

Topic: indentation for |>


view this post on Zulip Richard Feldman (Jul 08 2022 at 18:13):

should |> be indented by the formatter? Here are two alternative ways to format it: (using this as an example)

jsonNumArray =
    jsonNum
    |> sepBy (scalar ',')
    |> between (scalar '[') (scalar ']')
jsonNumArray =
    jsonNum
        |> sepBy (scalar ',')
        |> between (scalar '[') (scalar ']')

The first way (no indentation) is how F# formats it and also how Elixir formats it.

Elm indents it, but I happen to know that that's because when elm-format was originally created, infix operators were a userspace thing and it treated them all the same (so it would indent both |> and + the same way, because they're both arbitrary infix operators)

view this post on Zulip Richard Feldman (Jul 08 2022 at 18:13):

I can see some pros and cons to either

view this post on Zulip Ayaz Hafiz (Jul 08 2022 at 18:14):

Personally, I find the first formatting easier to read

view this post on Zulip Martin Stewart (Jul 08 2022 at 18:14):

Despite being used to indenting |> I think I'd prefer the first example as well.

view this post on Zulip Richard Feldman (Jul 08 2022 at 18:15):

two reasons that lead me to rethink whether defaulting to the way Elm does it is correct here (as Roc frequently does!) are:

  1. It's indented more, but it still seems very easy to me to tell what's going on in either version. So arguably it's causing things to be excessively indented unnecessarily.
  2. when you start a pipeline with a very short name, it doesn't look great in the mandatory-indentation version. e.g. compare:
jsonNumArray =
    it
    |> sepBy (scalar ',')
    |> between (scalar '[') (scalar ']')
jsonNumArray =
    it
        |> sepBy (scalar ',')
        |> between (scalar '[') (scalar ']')

view this post on Zulip Richard Feldman (Jul 08 2022 at 18:16):

I think if we do that, we should definitely automatically insert a blank line after the pipeline in defs

view this post on Zulip Richard Feldman (Jul 08 2022 at 18:17):

e.g. the formatter shouldn't permit this:

jsonNumArray =
    x = foo
    |> sepBy (scalar ',')
    |> between (scalar '[') (scalar ']')
    y = bar
    |> sepBy (scalar ',')
    |> between (scalar '[') (scalar ']')
    baz x y

view this post on Zulip Richard Feldman (Jul 08 2022 at 18:17):

instead, it should reformat to:

jsonNumArray =
    x = foo
    |> sepBy (scalar ',')
    |> between (scalar '[') (scalar ']')

    y = bar
    |> sepBy (scalar ',')
    |> between (scalar '[') (scalar ']')

    baz x y

view this post on Zulip Richard Feldman (Jul 08 2022 at 18:17):

or perhaps even:

jsonNumArray =
    x =
        foo
        |> sepBy (scalar ',')
        |> between (scalar '[') (scalar ']')

    y =
        bar
        |> sepBy (scalar ',')
        |> between (scalar '[') (scalar ']')

    baz x y

view this post on Zulip Martin Stewart (Jul 08 2022 at 18:18):

Richard Feldman said:

or perhaps even:

jsonNumArray =
    x =
        foo
        |> sepBy (scalar ',')
        |> between (scalar '[') (scalar ']')

    y =
        bar
        |> sepBy (scalar ',')
        |> between (scalar '[') (scalar ']')

    baz x y

I think this example looks best

view this post on Zulip Richard Feldman (Jul 08 2022 at 18:19):

a related question is whether other infix operators should be indented the same way

view this post on Zulip Richard Feldman (Jul 08 2022 at 18:20):

for example, this could be formatted as either:

if
    (byte >= 97 && byte <= 122) # lowercase ASCII
    || (byte >= 65 && byte <= 90) # uppercase ASCII
    || (byte >= 48 && byte <= 57) # digit
then

or

if
    (byte >= 97 && byte <= 122) # lowercase ASCII
        || (byte >= 65 && byte <= 90) # uppercase ASCII
        || (byte >= 48 && byte <= 57) # digit
then

view this post on Zulip Richard Feldman (Jul 08 2022 at 18:21):

and same with +, -, etc.

view this post on Zulip Richard Feldman (Jul 08 2022 at 18:21):

once again, I can see arguments either way! :big_smile:

view this post on Zulip Martin Stewart (Jul 08 2022 at 18:22):

I could go either way on those. Though maybe for consistency with |> other operators shouldn't be indented either?

view this post on Zulip Richard Feldman (Jul 08 2022 at 18:25):

an interesting argument for not indenting |> that just occurred to me: the operator works differently in Roc and Elm (in Roc it pipes the first argument; in Elm it pipes the last argument), so having a visual distinction if you're working in a code base that has both Roc and Elm code could be a nice reminder of which one you're dealing with!

view this post on Zulip jan kili (Jul 08 2022 at 18:30):

Do F# and Elixir pipe the first argument?

view this post on Zulip Richard Feldman (Jul 08 2022 at 18:32):

Roc and Elixir do it the same way, and F# and Elm do it the same way

view this post on Zulip jan kili (Jul 08 2022 at 18:32):

I like where this thread is going :)

view this post on Zulip Richard Feldman (Jul 08 2022 at 18:32):

F# and Elm do it that way because of currying

view this post on Zulip Richard Feldman (Jul 08 2022 at 18:32):

and Roc and Elixir aren't curried, so there are advantages to doing it the other way

view this post on Zulip Qqwy / Marten (Jul 08 2022 at 18:57):

I think this example looks best

This is also what is done in Elixir/ the Elixir formatter.


Last updated: Jun 16 2026 at 16:19 UTC