Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

F# style guide: How should long interpolated strings be formatted? #23306

Closed
cmeeren opened this issue Mar 13, 2021 · 8 comments · Fixed by #23365
Closed

F# style guide: How should long interpolated strings be formatted? #23306

cmeeren opened this issue Mar 13, 2021 · 8 comments · Fixed by #23365

Comments

@cmeeren
Copy link
Contributor

cmeeren commented Mar 13, 2021

The F# code formatting guidelines do not currently specify how interpolated strings should be formatted.

To give an example, consider this string:

let serviceStorageConnection = $"DefaultEndpointsProtocol=https;AccountName=%s{serviceStorageAccount.Name};AccountKey=%s{serviceStorageAccountKey.Value}"

Fantomas currently (fsprojects/fantomas#1511) formats this as:

let serviceStorageConnection =
    $"DefaultEndpointsProtocol=https;AccountName=%s{serviceStorageAccount.Name};AccountKey=%s{
                                                                                                  serviceStorageAccountKey.Value
    }"

Personally I don't find that particularly pretty, but long strings rarely are, and I don't really have a better suggestion right now. (Allowing deindenting interpolated expressions could help a lot here, though that belongs elsewhere. I won't bother with that right now.)

I can create a PR as long as someone can actually tell me how it should be formatted. I currently don't have any strong opinions. I want to note that the current way Fantomas formats it violates the "avoid name-sensitive alignment" clause, though without allowing deindenting interpolated expressions at the language level, the only ways out of that are 1) don't break (keep the entire interpolated string on a single line, or 2) (manually) break and concatenate the string. Personally I'm in favor of 1). Strings are the one thing where I don't bother keeping line widths.

/cc @cartermp @nojaf

@dotnet-bot dotnet-bot added the ⌚ Not Triaged Not triaged label Mar 13, 2021
@PRMerger9 PRMerger9 added the Pri3 label Mar 13, 2021
@cartermp
Copy link
Contributor

Yeah, I think we should add a section here to say that string literals (and interpolated strings) can just be left on a single line. Formatting like you poiint out doesn't really make a lot of sense.

@nojaf
Copy link
Contributor

nojaf commented Mar 17, 2021

What happens in case the user has an actual multiline expression interpolated?
Something like:

let str =
    $"""
    {
        let square x = x  * x
        let isOdd x = x % 2 <> 0
        let oddSquares =
            List.filter isOdd >> List.map square
        oddSquares [  1 .. 0 ]
    }"""

@cartermp
Copy link
Contributor

I certainly hope nobody ever writes code like that :)

But yeah, in the case of a multi-line interpolated expression (which is likely to be quite rare) it should be indented and the interpolated string needs to be a triple-quoted one.

@cmeeren
Copy link
Contributor Author

cmeeren commented Mar 17, 2021

But that "formatting" contains white space that is part of the string. If you don't want a line break or extra space before the expression, there is only one option allowed without compiler warnings:

  let str =
    $"""Here are all the odd squares from 1 to 10: { let square x = x  * x
                                                     let isOdd x = x % 2 <> 0
                                                     let oddSquares =
                                                        List.filter isOdd >> List.map square
                                                     oddSquares [  1 .. 10 ]
    }"""

This produces Here are all the odd squares from 1 to 10: [1; 9; 25; ... ]. Whereas this

let str =
  $"""Here are all the odd squares from 1 to 10:
  { let square x = x  * x
    let isOdd x = x % 2 <> 0
    let oddSquares =
      List.filter isOdd >> List.map square
    oddSquares [  1 .. 10 ]
  }"""

produces this:

Here are all the odd squares from 1 to 10:
  [1; 9; 25; ... ]

So I think that the only option is to indent multiline expressions where they occur.

I of course agree that no-one should ever write code like this, so I think formatting it "to the right" is fine (and again, I know of no other options). We can add an example like that and say that this is strongly discouraged. Do you agree?

@cartermp
Copy link
Contributor

Yeah, true. The indentation warnings in the compiler also prevent you from doing something like this:

let str =
  $"""Here are all the odd squares from 1 to 10:{
    let square x = x  * x
    let isOdd x = x % 2 <> 0
    let oddSquares =
      List.filter isOdd >> List.map square
    oddSquares [  1 .. 10 ]
  }"""

When you're in this kind of territory you're always going to be tweaking your code a little bit and I doubt it's the sort of thing an automatic formatter will be friendly towards.

Although the suggested alternative will work, I think people are likely to have highly specific formatting for their string that a set of guidelines may not work well for them here.

@cmeeren
Copy link
Contributor Author

cmeeren commented Mar 17, 2021

So for multi-line expressions, are you saying we discourage it but otherwise don't document the style, and Fantomas can just do whatever it wants?

(I think that's fine.)

@cartermp
Copy link
Contributor

Yeah, I think that's fine for now. If there's a bunch of demand for a standard then we could write one up.

@cmeeren
Copy link
Contributor Author

cmeeren commented Mar 17, 2021

PR updated.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

Successfully merging a pull request may close this issue.

5 participants