-
Notifications
You must be signed in to change notification settings - Fork 143
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
[style-guide] prefer leading rather than trailing operators #687
Comments
The style guide is quite incomplete when it comes to infix operators. Next, I do not see the parallel between the separators tokens of tuples and infix operators. Chained method calls are also a completely different topic, I again do not see the parallel with both operators and tuple separators. |
arguments:
This issue is to gather feedback, and most entrenched style guides of most entrenched languages, they seem to look over the points above, for some reason; maybe F# can break this line, if there is adhesion to the reasons or the overall feeling. |
For some reason I always find it considerably harder to read it when operators are shifted to the next line. When they're on the left operand line, they show that there's another related expression on the next line, and it reads naturally. The only exception for me is pipe operators, but they almost look like a part of F# syntax to me. |
One disadvantage I see from putting the operator on the next line is that it can break "indentation flow" let v =
expr1 //
+> expr2 if the chosen let v =
expr1 //
+> if a then
b
else
c The A disadvantage of putting the operator on the same line after the expression is that it can lead to indentation warnings and twist the meaning of the code. match [] with | [] -> 0 | _ -> 42 +
2 Instead of having the Another interesting case is that some operators cannot have the right-hand side on the next line, regardless of where the operator is placed. // not valid
"""long string
""" =
"""other long
string"""
// also not valid
"""long string
"""
= """other long
string"""
// valid
"""long string
""" = """other long
string"""
// also valid
"""long string
""" =
"""other long
string""" |
Not exactly sure what @smoothdeveloper is getting at in the OP; operators are currently by default placed at the start, aren't they? Is this then only about In any case, my two cents about some of the points in @nojaf's latest comment:
I think this is clearly a case of "bad code formats badly" and an acceptable limitation. Anecdotally, I've been programming F# full-time for five years, and regardless of the operator placement, I can't tell with reasonable certainty how that expression should evaluate. I would never publish it without testing it, which means I would refactor it so I wouldn't need to test it.
It does disrupt it a bit, but in the very few cases where I use a multiline expression in this manner, I am prepared to live with that as a limitation. What you show in that example is my preferred formatting. |
I found a compelling explanation under the "How to indent operations" of https://ocaml.org/docs/guidelines
A style being less adopted is just like a language which is less adopted, it doesn't mean something is bad about it.
Agreed, but F# causes the indentation challenges, and advanced editors and formatters evolve to incorporate the more advanced logic. Especially there are few constructs in F# that cause this kind of outcome, depending brace placement, etc. I think it is ok to overlook the particular offset that wouldn't match an integer multiple of the default indent size.
I created this issue as follow-up to this comment: #646 (comment) and I am happy to see fantomas already does that for many cases. I'd personally like F# style-guide adopt same recommendation as what it says in the OCaml guidelines, but I know it is not the default, but for very few languages. Some C# and C++ formatters support this for comma now :
|
Here's what Elm-style looks like, same for records (curly brace instead of paren). I've had a few cases where this made sense, usually method/constructor calls where I include parameter names for clarity and the line is too long. let madeUpTuple =
( moderate sized expression
, 42
, pipe |> into |> all |> the |> things
) Any way you choose requires 2-3 different selection approaches to copy/paste, depending if the item is first, middle, or last. And it's always a pain to move first item to last position and vice versa. I try to avoid multi-line tuples. Lead/trailing infix operators are subjective. I cannot stand trailing, with few exceptions. Probably built-up hate from VB line continuation chars. Also because operators stand out, they look out of place at the end to me vs lining them up at beginning. I feel like some F# styles already use non-tab-aligned code. (People who use this might also prefer 2-space tabs instead of 4 to avoid the issue.) let record =
{ Name = "foo"
IsActive = true } Same for lists. Always have to fix spacing after unindent in VS pro. 2 selection strategies required. I like just clicking line numbers and dragging to select. So I rarely use this style. |
It's only my personal opinion but I feel like all operators should generally behave the same: e.g. if pipe operator is moved to new line then and/or e.t.c. should be moved too.
|
This is a suggestion regarding position of operators in chained expressions
starting from:
I generally feel it is actually better (especially with long things) to put the operator in a leading position on the next line:
The same rule could be extended for
,
as well.Note that F# users tend to use
|>
operator in such manner.Also, most languages using "fluent notation" (chaining method calls), would put the
.
operator in leading position of next lineI've consistently felt it is more readable, easier to extend code, in many languages, using this type of positioning.
The text was updated successfully, but these errors were encountered: