fsharp / fslang-design

RFCs and docs related to the F# language design process, see https://github.com/fsharp/fslang-suggestions to submit ideas
517 stars 144 forks source link

[style-guide] Multiline application in patterns #717

Open nojaf opened 1 year ago

nojaf commented 1 year ago

Hello,

What should the guidance be for multiline (function?) applications in patterns? Example:

match myString with
| Regex @"^(\w+) can fly (\d+) km/s for (\d+) seconds, but then must rest for (\d+) seconds\.$" [ name; speed; flyTime; restTime ] ->
    ()

Imagine this pattern doesn't respect the max_line_length, how should it be formatted multiline?

This

match myString with
| Regex 
    @"^(\w+) can fly (\d+) km/s for (\d+) seconds, but then must rest for (\d+) seconds\.$" 
    [ name; speed; flyTime; restTime ] ->
    ()

comes to mind.

Related, patterns do seem to have some funky offset rules from time to time. The same example wrapped in a record:

match myString with
| { X = Regex 
            @"^(\w+) can fly (\d+) km/s for (\d+) seconds, but then must rest for (\d+) seconds\.$" 
            [ name
              speed
              flyTime
              restTime ] } ->
    ()

Notice that:

match myString with
| { X = 
        Regex 
            @"^(\w+) can fly (\d+) km/s for (\d+) seconds, but then must rest for (\d+) seconds\.$" 
            [ name
              speed
              flyTime
              restTime ] } ->
    ()

is invalid F# code. (online tool)

Another interesting case is:

match myString with
| X(
    Regex 
        @"^(\w+) can fly (\d+) km/s for (\d+) seconds, but then must rest for (\d+) seconds\.$" 
        [ name
          speed
          flyTime
          restTime ] 
  ) ->
    ()

This is valid code, thought the closing ) needs to be aligned with the X column.

@dsyme any thoughts on this?

abelbraaksma commented 1 year ago

Glad you brought this up, though function application in patterns, where there's more than one argument, is pretty rare. More often this is coded to accept a tuple. But that's besides the point you're trying to make.

Isn't your first example invalid code? You have this in the list code: [ name speed flyTime restTime ], but in the follow-up, you have the equivalent of [ name; speed; flyTime; restTime ]. Which really are two different things.

Those offset rules are a bit worrying though.

TBH: my vote would probably be for leaving it on one line. That's probably gonna be controversial (isn't everything related to formatting?).

But then again, that pairs pretty badly with a multiline list, seq or array construction.

Hmm, I recant that idea. To be in line with the other function application rules, aligning them like your first example appears most sensible, tbh. But any which way I look at it, it's hard to think of any formatting that would improve the readability of such code...

dsyme commented 1 year ago

I would say we should split like in the first example.

Related, patterns do seem to have some funky offset rules from time to time.

This seems like a bug and I can see it makes the splitting hard to implement.