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

Apply standard formatting across the board #73

Merged
merged 7 commits into from
Feb 12, 2024
Merged

Apply standard formatting across the board #73

merged 7 commits into from
Feb 12, 2024

Conversation

samritchie
Copy link
Collaborator

This applies pretty much just the default fantomas rules as a baseline & to get the monster diff out of the way. I’m not particularly religious about style so open to change if needed.

Also addressed previous test feedback in 9e08062

@bartelink
Copy link
Member

Not a bad idea in general. Have been meaning to get into it myself as it has reached a stage...
But there's def scope to tweak the default ruleset - @abelbraaksma has a lovingly tweaked ruleset in
https://github.com/fsprojects/FSharp.Control.TaskSeq/blob/main/src/.editorconfig - I worked in that repo for a while and it felt just like it was being 'correctly' formatted - then he goes and reveals its fantomas with good rules.
Unfortunately to deeply understand the ruleset is not a 2 minute job, but I anticipate starting from it as a baseline

Right, now I'll actually go look about what annoys me about the default ruleset, hoping to be pleasantly surprised!

build.fsx Show resolved Hide resolved
build.fsx Outdated Show resolved Hide resolved
build.fsx Show resolved Hide resolved
build.fsx Outdated Show resolved Hide resolved
| False
| True -> invalidOp "internal error: invalid query representation"
| Not q ->
! "( NOT "
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

this sort of stuff is just bad news - maybe if there was a prettier ignore annotation you could att at function level?

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pretty sure you can only ignore at file level

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

maybe thats the thing to do as the bulk of files do seem mostly fine overall

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

seems cured, will delete this thread after

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

wait, not sure why I thought it was cured, leaving comment here

@@ -515,11 +585,10 @@ type ConditionalExpression with
let values = aw.Values |> Seq.map (fun kv -> kv.Key, kv.Value.Print()) |> Seq.toList
expr, names, values

static member Extract (recordInfo : RecordTableInfo) (expr : Expr) =
extractQueryExpr recordInfo expr
static member Extract (recordInfo: RecordTableInfo) (expr: Expr) = extractQueryExpr recordInfo expr
Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think this is all based on line length - it’s not necessarily going to be consistent

@bartelink
Copy link
Member

OK, ultimately I know fantomas is the right thing to do
But it's got some really painful defaults, and F# the language is not as amenable to blanket rules as some noiser languages

The result is that it works really badly with handf ormatted consistent code like equinox, e.g. jet/equinox#345 (see my mainline comment there on my stance)

What to do here? Main thing is to measure twice, cut once.

The main risk here is that a hand formatted parser with necessarily large blocks of logic which is non trivial to understand is really not helped by being stretched to twice the line count - there were enough of those in my quick traverse to nor make me want to do it if it was my project.

While the formatter demonstrates that Eirik was not 100% consistent, ultimately his code in 2014 was setting standards for legible layout without any fantomas in the picture. Regularising it is going to lose some value. But there is a win too if it aligns with sister projects that people are likely to have read and/or eventually will read in conjunction with it.

My hunch is that taking the TaskSeq ruleset and living with that might be a better answer as it didnt offend me too much despite being picky and working across plenty projects.

But I won't fight on using the defaults, as plenty projects do that and its not like the fantomas folk dont have internal style debates.

@bartelink
Copy link
Member

also nojaf (was going to at him, but people have enough to do) and I have yet to apply it to Argu, which will likely have similar issues
Can't see it working on TypeShape either for similar reasons that the parser logic gets mangled.
would nearly at Eirik here but he's done enough for us to not deserve the harassment of being dragged into a style debate

@samritchie
Copy link
Collaborator Author

Okay, I’ve been through the TaskSeq config and removed the obsolete settings etc.

Still no luck with the pattern

if condition then doSomethingOnOneLine
else dont
  • it seems to be either all on one line, or split across 4. elifs seem to allow the case body inline though

With the space-before-DU the only setting is fsharp_space_before_uppercase_invocation which is also going to catch MethodCall ()

Agree in general re formatters - I avoided them for a long time but they are quite liberating once you get used to them. Sure it doesn’t always result in code the way I would have done it, but I didn’t have to do it...


let names =
aw.Names
|> Seq.map (fun kv -> kv.Key, kv.Value)
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

maaaan (though the answer is to rewrite it as [ for kv in aw.Names -> kv.Key, kv.Value])

sprintf "Document path '%s' not found." id.Name |> KeyNotFoundException |> raise
sprintf "Document path '%s' not found." id.Name
|> KeyNotFoundException
|> raise
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

argh! I guess the rule is >=2 pipes means multi line
I'd prob write raise (KeyNotFoundException($"...")) if it did this to me
but fine

@bartelink
Copy link
Member

Looking better but seems cure is worse than disease if spaces before DU ctor args means space before method args and all other ctor args
If we get it down to one or two nigglies and are continuing, then in the end we might at in nojaf to see if there is a workaround/better solution

@bartelink
Copy link
Member

Okay, I’ve been through the TaskSeq config and removed the obsolete settings etc.

It does seem to be getting decent
one line ifs are prob not the end of the world even if I really like them
but I also like trailing else with a blank line for early exits too

Can prob do stupid things like converting ifs to matches to fight the formatter lol

override __.GetHashCode() = hash expr.Attributes
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

also need to do an F# syntax update - Rider can bulk fix these

sprintf "Document path '%s' not found." id.Name
|> KeyNotFoundException
|> raise
sprintf "Document path '%s' not found." id.Name |> KeyNotFoundException |> raise
Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I’m not sold on one-lining these, having the raise at the end of the line is less obvious than having it at the bottom of the chain. I can experiment with winding back the infix expression length a bit but the likelihood is it will catch some & not others.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

yes 2 pipes on a line is def the limit
and I prefer the raise to stick out
as mentioned I'd map that to raise (KeyNotFoundException $"...")
but sreading it over 3 lines doesnt really help anyone IMO other than forcing them to think, which is great of course

values
|> Seq.map (function
| AttributeGet qa -> qa
| _ -> invalidExpr ())
Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

There doesn't appear to be a max expression length for match/function; it always breaks.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

maybe that's not the end of the world in this instance - it can work well for short one liner option matches, but I guess its also something that gets taken too far (speaking personally 😊 )

@samritchie
Copy link
Collaborator Author

Picking this up again - the main change I’ve made is adding the fsharp_experimental_keep_indent_in_branch for early exit.

I’ve also turned off fsharp_blank_lines_around_nested_multiline_expressions - this is imo the one that annoys the most because you hit length limits then suddenly you have 15 lines instead of 3. Effectively with fsharp_keep_max_number_of_blank_lines set it’s going to allow the author to insert/delete blank lines which are preserved (in most cases). I’ve gone through and manually tidied some blank lines where it looked like it made sense but it’s very subjective.

@samritchie
Copy link
Collaborator Author

I think the main part that’s still substantially ugly(er) than previous are those multiple-expression-lines in the query writing code. The option is always there to exclude those and manually format but it’s probably not worth the tradeoff. @bartelink I agree most of the other quirks would be better handled by changing code structure instead. When that will happen I don’t know though...

@@ -281,11 +271,9 @@ type ManyReadOnlyItemsFixture() =
let table = base.CreateEmpty<MetricsRecord>()

let hk = guid ()

do
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

for these, I'm wondering if the do can go on the same line, or does it separate it if you do (very minor of course)

@bartelink
Copy link
Member

Looks to have worked very well. On balance its positive for the codebase so I'd call it done.
'We' should try to do basic language updates per Rider suggestions pretty soon as a follow-up.
All that remains is to ponder whether and when I want to do this to github.com/jet

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

Successfully merging this pull request may close these issues.

2 participants