Why is switch formatted like this?

From the playground example

module Button = {
  @react.component
  let make = (~count: int) => {
    let times = switch count {
    | 1 => "once"
    | 2 => "twice"
    | n => Belt.Int.toString(n) ++ " times"
    }
    let msg = "Click me " ++ times
    <button> {msg->React.string} </button>
  }
}

Looks good, now put a block at 2

module Button = {
  @react.component
  let make = (~count: int) => {
    let times = switch count {
    | 1 => "once"
    | 2 => {
        Js.log("picked 2")
        "twice"
      }

    | n => Belt.Int.toString(n) ++ " times"
    }
    let msg = "Click me " ++ times
    <button> {msg->React.string} </button>
  }
}

Why does the block at 2 need an seemingly arbitrary blank line after it? All it does for me is hurt readability because the choices are less mentally scanable.

Here’s an example from my own code. There’s no reason for anything here to have blank lines, but look who shows up.

describe("mydesc", () => {
  testPromise("something", ctx => {
    let sql = `insert into users (id, email, password) values (1,'me@example.com', 'asdf')`
    ctx
    ->getDb
    ->DalLoad.go(sql)
    ->Promise.then(
      _a => {
        DalUser.get(ctx->getDb, "1")
      },
    )
    ->thenResolve(
      maybeUser => {
        switch maybeUser {
        | Some(user) => {
            Js.log(user)
            chai->equal(user.id, "1")
            chai->equal(user.email, "me@example.com")
            chai->equal(user.password, "asdf")
          }

        | None => chai->fail("missing user")
        }
      },
    )
  })
})

p.s. The Promise.then is also putting in newlines for no reason, but at least there aren’t two in a row.

I don’t think this is related to the switch, but the {…} block. If you remove it, then the formatter doesn’t add a blank line. (The {…} doesn’t actually do anything in the original.)

module Button = {
  @react.component
  let make = (~count: int) => {
    let times = switch count {
    | 1 => "once"
    | 2 =>
      Js.log("picked 2")
      "twice"
    | n => Belt.Int.toString(n) ++ " times"
    }
    let msg = "Click me " ++ times
    <button> {msg->React.string} </button>
  }
}

The formatter seems to add blank lines after blocks in other places, too. Here’s a contrived example where it adds a line:

let f = () => {
  {
    Js.log(1)
    Js.log(2)
  }

  Js.log(3)
}

But to answer why it does this, I don’t know. Maybe this is something the formatter could be “smarter” about.

Well I feel stupid now, but that solves my problem :wink:

1 Like

Basically there’s already an automatic block after the => in a switch. Adding an extra { } just creates another nested block, which is a no-op.

IMO, the most consistent thing the formatter could do would be to just remove the redundant { } for situations like this. Either way, I think this current behavior is definitely confusing.

I like code blocks :sweat_smile:

Right, because if there {} around a single line it removes it automatically, but if its around multiple lines it doesn’t, which misled me into thinking an explicit multiline block was necessary.