SE-0250: Swift Code Style Guidelines and Formatter

(Yasuhiro Inami) #104

+1. I think nobody will complain if the formatter is flexible enough to customize rules for each project.

For "default" style guide, I would highly recommend to follow existing Xcode style (especially indent) since it is probably the current de-facto standard in Swift community.
Without it, many people will probably keep complaining (and perhaps I will!)

1 Like
(Tino) #105

I don't think the wording fundamentally changes the meaning, so the interpretation actually doesn't matter much.
Wether it's called "official", "recommended", "default" or "mandatory" style, or even "arbitrary choice of styling parameters that happens to be delivered with the formatting tool bundled with Swift, without implying that any other choice of parameters is worse" - in the end, it always boils down to the same result:
If you disagree with the set of blessed rules, it is very likely that you run in situations where you have to defend your opinion.
As it has been pointed out several time before, you simply can't have the positive aspect (uniform styling of code) without paying a price in discrimination and pressure. Therefor, the proposal is simply shifting Swift in the direction of more discrimination, and the wording merely changes how much pressure is applied.

It might be justified to take this route, but my impression is that the proposal tries hard to suit everyone, which is outright impossible.

5 Likes
(👑🦆) #106

That's not how things work in real life. You'll have a codebase which uses particular styling, then some new programmer will come along and ask why things aren't in the "official" style. Your manager (who doesn't know Swift and hasn't read this lengthy discussion) will get wind of that and assume this means there are bugs or incorrect code or something. As @Tino says: you'll start having to justify it all the time, mostly to people who have much less experience of Swift and the actual codebase than you do. Depending on the word we choose you'll have more or less of an uphill battle, but you'll have a battle all the same.

Again: why even go down this road? Having a blessed-but-not-mandatory style sounds like a compromise, but IMO results in the worst of all situations.

3 Likes
(Nathan Harris) #107

I wonder if the nature of the discussion would change if this came from a different perspective.

What I would perfectly happy with, and would find actually valuable for the SE effort, is if the proposal was for the Core team to adopt an Official Style Guide for all code within the Official Swift projects.

That would place the enforcement entirely on the projects outlined in the motivation - SwiftNIO, Foundation, SPM, STDLib, etc.

Then, projects such as Vapor and other projects such as NIORedis could choose to adopt the official style - and tool - as is, as the goals of those projects are to mesh with the Swift projects as much as possible.

But other teams and projects, such as app developers, CLI tools, etc. could choose to ignore it - as their goal is to just deliver an end product - not necessarily a framework.

We still get the benefit of having an "Official Source of Truth" - but also the fact that the style guide is meant to manage The Swift Projects not Swift developers.

9 Likes
(Erica Sadun) #108

I don't believe we should endorse a single blessed universal Swift style, which most users would feel obliged to adopt (even if they are not forced to). I would much prefer to establish a style sheet format that may be applied by Xcode or via the command-line, allowing different groups to automatically apply preferred formatting.

Code style supports an audience.There are many audiences out there, not a single monolithic one. Consider applying the typical stdlib style to the most trivial lesson code. Is this the kind of Swift we want to present to new users? It's unambiguously hideous for that purpose:

// Typical stdlib style
internal final override func _projectMutableAddress(
  from base: UnsafePointer<Root>
  ) -> (pointer: UnsafeMutablePointer<Value>, owner: AnyObject?) {
  // Since we're a ReferenceWritableKeyPath, we know we don't mutate the base
  // in practice.
  return _projectMutableAddress(from: base.pointee)
}

// Matching stdlib style
func greet(
  name: String
  ) -> String {
  return "Hello \(name)"
}

// Typical style for teaching
func greet(name: String) -> String {
    return "Hello \(name)"
}

Wide tabbing, and simple declarations make it easier to present and grasp the core language. Short tabbing, limited line extent, line-based parameter declarations all support production values like easier diffs and code reading in printed form. This proposal assumes a uniform set of users, which is antithetical to the notion of a general purpose language.

While some parts of the language have developed community consensus as to their application, others have not. For example, using parentheses around functional closures and raw braces for procedural ones is a style with measurable benefit but minority adoption.

While no one will "force" anyone to use the standard Swift style, given the example of the switch statement, there's no doubt that any given style choice will dominate. It's not worth fighting the editor or the standard format, regardless of how ugly the result. It's already bad enough trying to place the else clause braces with guard. Should we have to fight the tools to adopt the minority functional/procedural style just because it's not widely used by the arbiters of "standard"? What about those groups that use mandatory self? Or mandatory internal binding? Standard style will exclude many kinds of well-considered safety choices and has the potential to incorporate unpopular ones.

Beyond trivial consensus like left-magnetic colons and commas, every single automatic styling decision is going to have to be fought in the public forum or decided by fiat. Neither outcome is a happy one. A standard style shouldn't be "everyone program like Google". We've seen bikeshedding and this has the potential to be the bikesheddiest bikeshedding ever. Plus the vast audience of users who do not participate in SE will have little say over the outcome. Compare this "Swift will adopt a standard style guideline" with SwiftLint, where adopted rules can be included or excluded by each house team.

To be successful, a Swift code style guideline sheet should be adaptive, and support multiple modalities appropriate to their audiences. The proposed toolset doesn't do that. SwiftLint does.

The proposal concerns are:

  • Inconsistent style within projects: This is solved by linting.
  • Code review focused on formatting issues: This is solved by linting.
  • No "best practices" community consensus: I disagree that this does not already exist and is addressed by SwiftLint's default rule set.
  • Cognitive burden of inconsistent community consensus: A consensus already exists across many projects for core styling choices but these choices are trivial.

Should the Swift language adopt a set of code style guidelines and a formatting tool?

I'd answer: "not as proposed", and certainly not without configurable rule-driven application of language formatters. Yes, let's have a linter and formatter but no, there is not one style sheet to rule them all and in the Swiftness bind them. Nor would it be healthy for the SE community to rigorously work through the minutia or good for the extended Swift User community to be compelled by (unenforceable) fiat to adopt them.

23 Likes
(Boris Triebel) #109

Just want to say that i am super grateful for your posts on this. Both because i could simply not express it as well as you do and because it saves me the effort. And obviously the two aspects are related because i would post at this point if writing a proper spelled out argument with sensible diplomatic wording would take less time. So thank you.

1 Like
(Boris Triebel) #110

I think this would be a much better approach. Start with a core. More efficient communication about the style guide between a smaller group. This group also has a greater ability to agree on some smaller subgroup of people to work out the details of a proposal. if successful: Rest of the community can use it as reference. If it works well: Maybe continue this discussion to make it official for everybody.

3 Likes
(Preston Sumner) #111

I'm in favor of default style conventions and a formatting tool to enforce them, including whatever degree of configurability would meet that goal.

In the pitch thread, I compared this to the automatic formatting provided for manuscripts and screenplays by word processors. Those tools exist so that writers and readers rely on the same visual cues to scan content. In my opinion, consistency is more important than personal style, especially in today's globally connected environment. Just as the focus in a manuscript should be on the content, the focus in a source file should be on the logic. I'm sure teachers, for example, would appreciate the reduction in the degree of "creative expression" in code formatted by new programmers.

One counterargument is that the official establishment of a default style would eliminate preferred styles or tools, but that's addressed by the fact the tool will be optional. If you don't want to use it, don't. Or configure it, if that addresses the concern. Or use an alternate tool.

A related counterargument is the social angle: the fact there will be a default style and an included formatter will most likely establish an official canonical style in the minds of most. But, of course, the point of a default style is to be widespread. Otherwise, the goal of consistency is unachievable. Therefore, the style must necessarily be perceived as "vanilla Swift," and this is a good thing.

Users already answer style decisions by copying Apple's sample code and WWDC presentations, along with whatever formatting inconsistencies are included in them (hopefully to be addressed by this formatting tool as well). Much of Swift's style comes from what we saw from Apple when Swift came out, the rest deriving from whatever common Objective-C conventions translated well. The rest is full of esoteric details, the sorts of details a formatting tool will eliminate arguments over. After the subsequent community debates decide them, anyway.

Which leads to my final point about impending community debates if this proposal is, as I hope, accepted. The potentially extensive debates over the conventions and best practices to enforce will be a good thing. Let the energy be expended and the arguments be made so that users don't have to. Compare styles, relate experiences, and attempt to determine which visual cues serve best in most cases. It will be especially interesting to hear from maintainers of large projects like swift-corelibs-foundation.

5 Likes
(Paul Cantrell) #112

I know I said I’m bowing out, but since Erica is here … one more post.

This is incisive. I’d like it framed.


Reading Erica’s thoughts, I realize I’d be more amenable a different proposal: a configurable autoformatter with per-directory (and perhaps per-file) config, built so that individual projects that have reason to deviate can do so without endless tool friction.

The config needn’t be comprehensive or fine-grained at first; it could simply allow disabling categories of rules. It would then be the defaults and the config format, not the tool per se, that get the blessing of swift-evolution.

Advantages:

  • This could still fulfill the wish to end team style debates by providing well-vetted default settings. Teams who don’t want to think about it can just declare “defaults and done,” which is equivalent to choosing to adopt a zero-config formatter.
  • Teams who wish to follow conventions in general but have one or two minor departures from the defaults for project-specific reasons aren’t shut out of using the tool entirely.
  • Teams who want more tightly controlled style could in principle enable rules that are off by default, instead of having to run a second stricter autoformatter.
  • Teams who depart wildly from the defaults can opt out of the autoformatter in a standard way, so they don’t get pull requests full of meaningless formatting changes just because a careless contributor hit “Save” in their editor.
  • All of the above means the tool can be a bit more aggressive about its styling by default. Allowing rules to be opt-out means less pressure to please everyone.
  • This in turn means that we could perhaps expedite the rule selection process (e.g. by choosing a benevolent dictator, running an existing code scan, or just adopting Swift stdlib conventions) and thus avoid the Great Style War to Come.

The disadvantage is that you don’t get perfectly consistent “you never have to look at an unfamiliar style” code. For reasons stated above, (1) I don’t find this a compelling goal in general, (2) I specifically don’t think this is a wise goal for Swift, and (3) the proposed formatter won’t necessary grant that wish anyway.

A direction like that is something I could live with much more happily.

Edit: I realize I am describing SwiftFormat — and indeed I wish this nice-looking new tool were simply another open source offering. But if there is going to be a standard, officially blessed formatter that starts creeping into dev environments and being enabled by default in some editors, a standard way to partially or fully disable it would make that much more palatable.

4 Likes
(Mox) #113

Being able to disable (or enable non-default) rules is what swiftlint and many other linters do. You can disable a rule within single file with special code comment, or you can disable a rule for entire project / folder with a config file located in desired folder.

(Karoy Lorentey) #114

The decisions a coding style would make seem superficial to me. The syntax of a language does absolutely affect its audience -- but I don't see how spacing/line-breaking guidelines would do the same.

What possible difference does it make to any audience whether or not the Standard Coding Guideline prefers to put a space before the colon in Foo<C : Collection>? This is a great example of the kind of pedantic decisions the Guideline would make.

As a stdlib engineer, it pains me that I have to point this out -- but the repulsive style below is emphatically not, and it never has been, the coding style of the Swift Standard Library:

I'm shocked you'd think stdlib people would make a twisted mess like that. We'd write it exactly like you suggest:

Line breaks only come in when a line exceeds the length limit. The limit is set to 80 in the stdlib, which is unusually small these days. Like any other stylistic choice, it has some practical advantages during our work. It does lead to more frequent line breaks, which is one of its disadvantages. Ultimately it's a trivial and utterly boring detail, like any other reasonable stylistic choice.

For reference, the style exhibited by the "prettier" tool in @mattt's blog post seems the closest to the stdlib conventions amongst the tools he tested.

However, none of this is relevant here, since the proposal isn't about adopting the conventions of the stdlib project (or anyone else).

15 Likes
#115

Okay, now I'm getting confused because this is exactly how swift-format, the proposed tool, works.

and there is a whole section in the proposal about being amenable to adding various axes of configuration.

2 Likes
(Stern) #116

After reading both threads it seems like we are putting the cart before the horse. It seems to me we should have the style guide first and the tool second. This proposal seems all about adopting a proposed tool before we have a style guide. Or perhaps to do both at the same time.

As far as I'm concerned Swiftlint works for me. I don't need some rush job to build a formatter. I like the swiftlint autocorrect style well enough. If you look at the issues page on the swiftlint GitHub project you'll see a ton of issues. Almost all of them are requests for more lint rules. Almost none of them are complaints about the formatting or requests for different formatting. Developers that have adopted the swiftlint format don't appear to have complaints about it. I don't think it's as hard to come up with a swift style guide that would be generally accepted as some seem to think.

Let's build a style guide. The tool can come later.

1 Like
(Paul Cantrell) #117

The configuration of the existing tool is quite limited, dealing only with mechanical things like line breaks and indent size — text editor config stuff, not fundamental style choices.

The proposal explains this:

swift-format will allow configuration of some practical formatting decisions like indentation size, line length, and respecting existing newlines. In mixed-language projects, some tools in a developer's workflow may not easily support configuring these on a per-language basis.

The proposal does also suggest that there is some hypothetical flexibility to add more configuration:

We are also willing to consider additional degrees of configurability. A tool that is not configurable only works for users who are completely satisfied with the defaults. A tool that is configurable is still usable by anyone who wants to leave it configured to the default settings, but can also be tailored to the unique needs of individual code bases. Even if style guidelines ratified later encourage a particular default configuration, users with different needs should still be able to reap benefits from using the tool.

…but the motivation section of the proposal suggests that consistency, not flexibility, is the primary goal of the tool:

Developers can move from one codebase to another without incurring the mental load of learning and conforming to a different style

…which certainly does not suggest that config will support many style options. I’ve heard no suggestion from the tool authors that it is a design goal to make it support a wide range of formatting styles. They can correct me if I’m wrong.

If the tool is in fact completely optional, completely configurable, open to a multitude of style options, and has to be added to one’s workflow manually, I wonder why the tool (as opposed to an abstract style guide) even needs to go through Swift evolution process at all — as opposed to merely being released as a (possibly better) open-source competitor to the existing project whose name it duplicated.

Again, reading the supporting posts on this thread, the support seems scattered inconsistently along the consistency/flexibility continuum. See above.

2 Likes
(Karoy Lorentey) #118

In my reading of the proposal, the new tool would be mostly limited to inconsequential text editor stuff — the proposal calls it a formatter, not a linter.

A formatter’s primary job is to automatically normalize the whitespace between tokens, without touching the tokens themselves. It must be reliable enough to be blindly trusted to do its job without ever corrupting code — to the point that we could mechanically reformat files in a commit hook if we wanted.

A formatter could also come with a limited set of entirely non-controversial and 100% reliable syntactic transformations (things like SwiftLint’s Modifier Ordering rule). Ideally these would not be enabled by default.

As I imagine it, the tool would be something along the lines of gofmt, not SwiftLint. (Which is not to say SwiftLint is bad — it’s just a different tool entirely. There is room for both.)

To use an analogue from book publishing: A formatter is to a linter like a typesetter is to a copy editor. The principal output of a good typesetter is a tastefully formatted book containing exactly the same words that are in the author’s original manuscript. The output of a copy editor is a list of editing suggestions that need to be individually approved or rejected by the author.

I believe this proposal is asking (1) if it’s a good idea to have a Chicago Manual of Style for Swift programs, and (2) if it’s a good idea to create an automated typesetter for its formatting rules.

My answer is to both is an enthusiastic yes.

14 Likes
(Tino) #119

That's a perfect example for what I've been trying to convey: Style can be a very emotional thing, and it really doesn't sound like you need nothing but a short adjustment period to realize the virtue of this particular formatting…
Sure, most likely, no one will force you to switch to "pseudo-stdlib"-style - but this discussion is about urging other people to write their code in a way they might despise in the same way that you dislike what has been shown in the snippet.

I thought a diverse and welcoming community was an important aim for Swift - but here we are, debating about a change that would establish one single "right" way to format code, thus telling many people that their preference is slightly wrong, and their work is flawed.

5 Likes
(Karim Nassar) #120

After reading this thread and the pitch thread, I’m firmly -1 on this pitch as it stands. @Paul_Cantrell and @Erica_Sadun have really expressed my feelings on this better than I could.

At the end of the day, I think that this pitch was approached from the wrong direction. IMHO, a better approach would have been to assemble, publish, and evangelize a style guide based on current community practices and let it evolve and gain traction organically. Then when a concrete style guide has formed that has consensus support, propose formal adoption of that style, and only then propose any new tooling, etc.

This would have the advantage of allowing existing tools to leverage the evolving style, let developers “try it out” over time and in real projects to find any flaws/misses, and would eventually produce a stronger, more universally adopted style guide, even if a single “official” tool never materializes.

10 Likes
(Jacob Williams) #121

This sounds like we should just take SwiftLint's or SwiftFormat's default rules and apply them to a pitch/proposal to make them the officially recommended set of style guidelines.

Both have reasonable defaults and have already gained pretty widespread adoption (been around for several years and used by thousands of swift devs). It sure beats starting from scratch and fighting (to the death) to come up with a totally "new" set of rules that will probably match 95% of what SwiftLint and/or SwiftFormat already use anyways.

(Tony Allevato) #122

The proposal authors are explicitly not debating that:

The proposal authors wish to emphasize that we are not proposing that users be required or forced to use a particular set of style conventions. The Swift compiler will not be changed in any way that would prevent otherwise syntactically valid code from compiling. Users who wish to reject the style guidelines and adopt a different style for their own projects are free to do so without the tooling pushing back on that decision.

We have no desire to "establish one single 'right' way to format code"—we wish to establish recommendations and tooling to support those recommendations. Those recommendations and tools clearly won't satisfy everybody, and those folks are free to not use them without penalty or pushback.

But for every one person who feels that that strongly, there are probably hundreds who just want to get work done with tools that get style concerns out of their way. For those users, having a solid out-of-the-box experience is a productivity boost, as it also is when switching from project to project without having to worry about the nuances of project-specific style.

The sentence you quoted is not mutually exclusive with consistency. If a tool permits configuration such that different projects can make different style choices, the ability of a tool to apply those choices automatically still reduces the mental load of conforming to that style.

Furthermore, it removes the need for project owners to focus on style concerns when reviewing contributions from newcomers. This provides a much smoother ramp-up experience for anyone considering contributing to a project for the first time, especially compared to (1) the user having to spend extra time making sure they've internalized all the nuances of a project's particular style by trying to infer them from existing code, or (2) the user feeling disincentivized because a project owner has to spend time correcting numerous code style nits that really ought to be trivially and mechanically taken care of for them.

This isn't quite accurate; the name swift-format was chosen because the hope was to create a more robust SwiftSyntax-driven tool that would replace the Swift driver executable of the same name that is currently distributed with developer snapshots.

Exactly, and that's an important part of the proposal review process in my mind. The pitch thread yielded input ranging from "the tool should be completely configurable to support many personal styles" to "the tool should support a single canonical style", and that's a sign that we aren't going to satisfy everybody completely—but that's also an unrealistic requirement. Even so, we want to get that feedback and consider it because it will help to guide us. Just as feedback from the pitch thread led us to update the proposal text to clarify certain aspects, feedback from there and here will help guide how we prioritize certain aspects of configurability, should it be accepted.

2 Likes
(Rex) #123

If you’re looking for feedback, I find that any linter/formatter that does not support “enforced use of self.” as an option a non-starter.

Edit: Looks like SwiftFormat supports requiredself and then some. I’d also prefer it, then, as the tool to integrate.