SE-0250: Swift Code Style Guidelines and Formatter

(Jeremy David Giesbrecht) #164

That is a very good question. My understanding was based on @allevato’s comments and posted links, the read‐me file, the repository’s Documentation subfolder, etc. The directory you found makes it look like there is far more implemented than the documentation implies, so maybe I was wrong. @allevato, do you have clarification?

That is Google’s internal style guide for its former Swift for TensorFlow project and not directly connected with swift-format or this proposal. (Though due to stemming from the same company, it does probably describe the style the authors of swift-format are most accustomed to.)

Since that style guide has been brought up, I will share my thoughts about it—but only in an abstract sense that informs on what the general scope and philosophy of the proposed style guide should be. Largely I agree with Google’s style guide. The parts I dislike fall under two classes:

  1. Rules that do not make sense for a code base not written in English (such as the ASCII recommendation for identifiers). Such a rule makes perfect sense for a company whose working language is English, but not for a company whose working language is Chinese. It would get annoying fast if the formatter flagged warnings for this. However, a more abstract rule that lets the project configure its preferred set of characters would be welcome, since neither team likely wants Russian letters sneaking in and vice versa. Since participation in these forums is largely dominated by the English language, I am a little worried that the developer communities who code Swift in Portuguese, Japanese, etc. and have less voice here will end up with a tool working against them in these sorts of ways. I hope that outcome can be consciously avoided by review managers.

  2. Rules that are at odds with Xcode right now. For these, I really don’t care which style it is, as long as it is consistent. But it becomes annoying when the various tools are fighting against each other. This point is actually in favour of the proposal at hand though, since it would help resolve the disparity in one direction or the other: Xcode would adopt the standard style, or the standard style would adopt Xcode’s way. Either way, problem solved!

Bonus points for a standard configuration file that Xcode and other tools can all read and obey, like how any tool can read a package manifest using the SwiftPM package.

3 Likes
(Tony Allevato) #165

swift-format splits its implementation into two phases. Phase 1 (the SwiftFormatRules module) is syntax-tree-based transforms, like sorting imports, stripping unnecessary parens around Boolean conditions (e.g., if (x) -> if x); basically things that for the most part don't involve whitespace or wrapping. Phase 2 (the SwiftFormatPrettyPrint module) is where we handle line-wrapping, indentation, and so forth, by describing how the parts of specific syntax nodes should be line-broken. It's not 100% complete in terms of syntax nodes, but it's fairly close.

It's also used by the various iOS apps released by Google that use Swift. We made it public at the time that we finalized it internally just as we make public our style guides for other languages (http://google.github.io/styleguide/), as something that people can adopt, base their own off of, or ignore as they wish.

So to @Tino's comment about "decisions that have already been made", they've only been made for projects within Google. Furthermore, if any "default style guidelines" that come out of this process end up differing from what is in Google's current style guide, then Google's style guide would be updated to adopt those changes (I can say that, because I'm its owner), because we would want our style to be the same as what the community decides is a good default.

Google's style guide served as the basis for the implementation of swift-format because it makes sense that we would implement rules that we're familiar with, but even the current implementation of swift-format differs from Google's style guide in a handful of ways (mainly because we wanted to make sure that our implementation handled other possibilities and that we didn't hardcode any assumptions based on our own style). The pretty printer implementation is nicely parameterized and generic such that we could change its behavior or make it configurable with relative ease.

And I think this is a prime example of why we clearly have no interest in foisting Google's style guide upon everyone. There are rules that make perfect sense for us internally that don't hold for broader audiences.

I mentioned this earlier up-thread, but I think some of the concern that people have stems from how they're interpreting the word "adopt", which means I should have been clearer in the proposal. If this proposal is accepted, in no way is the current version of swift-format going to start being included instantaneously in Swift release toolchains. The source would be pulled into the project where it would continue development and eventually serve that purpose, after suitable default style guidelines were decided upon.

4 Likes
(Tino) #166

I'm getting more and more confused:

It is a living document and the basis upon which the formatter is implemented.

Which formatter is referenced in the guide??

Update: As I understand Tonys answer, swift-format is directly connected to the guide — so at least it looks like I'm not the only one who got confused ;-)

Given the fact that the proposal has a somewhat hidden link to a detailed styleguide, I'd like to know what exactly should happen if it is accepted:

  • Will there be a proposal for each rule?
  • How can we ensure those proposals are neutral, and not biased by the choices that have already been made?
  • What will be the schedule, and when will the process be finished?
1 Like
(Tony Allevato) #167

I think this is implying an intent that isn't there; we're not trying to hide anything. The formatter's current implementation started from Google's style guide (but the current version differs even from that), but that's purely an artifact of where it was developed (and because we wanted a couple teams internally to be able to test it effectively). The specific rules it applies might serve as inspiration for rules proposed in the future, but they would presumably go through some process involving community discussion.

If you're concerned about bias, keep in mind that:

  • I'm not a member of the Swift core team or employed at Apple, so my personal opinions matter very little here
  • I trust the core team to come up with a process for proposing style guidelines that is effective and fair
  • I certainly don't want an entire community of developers cursing my name for eternity :wink:
4 Likes
(Ben Cohen) #168

I am a strong supporter of there being an official tool, that ships as part of Swift, that formats code in a particular style. That tool should be without configuration options to tinker with, other than column width. It should be an easy and natural decision to adopt it (though of course optional to do so).

I review and consult on a lot of Swift code, from all sorts of teams and from all sorts of places. Many of those teams are new to Swift, and are coming from Objective-C, C++, Java, Python and other languages. These new Swift developers are clearly struggling to find the best way to format their code. Often a single project will show 3 different styles of formatting: the way code comes out from using Xcode; the standard library/llvm-ish format; and the formatting style of the language they are coming from.

Personally, I find it very distracting, when trying to quickly understand a medium-sized code base, to find it chopping and changing like this. But more importantly, it must be distracting for these developers, who are trying to learn a new language with new idioms and vocabularies, to have to also deal with trivial formatting decisions. We should be doing everything we can to help them become comfortable with the language as quickly as possible, and one great way to do that is to give them a smooth quick path to writing code that "looks and feels" right; that looks like the good sample code they see, like the code in evolution proposals, and like code in the standard library* and other core libraries. This is the win that a simple consistent way to format your code, performed by a tool that ships as part of Swift, will provide.

* this does not presuppose the standard library's current format is the format that will be adopted. The standard library should be reformatted to whichever style is adopted.

31 Likes
(Xiaodi Wu) #169

This goes to the heart of the issue; it also demonstrates why, in my view, substantially what is proposed in this proposal is inevitable.

As @Ben_Cohen points out, the standard library/LLVM-inspired format differs from the format used by default in Xcode, which itself is distinct from that of The Swift Programming Language and other Apple documentation. In each case, some style has already been adopted, since the mere fact of there being code forces a choice as to where to put braces and colons, how to indent, and so on.

I would posit that the principal reason why Swift does not already have an official style guide and formatter is that there is no single first-party style. Consider: if Apple were to adopt a single style across all of its documentation, cause Xcode's default formatting to match that style and the compiler-generated interfaces to use that style, and align Swift code in the standard library and core libraries to that style--which, of course, would necessitate the creation of a tool to automate that process--then essentially everything proposed here would already exist, all without Swift community input!

The style choices made for the Swift project itself and Apple's Swift-related documentation, APIs, and developer tools are not strictly internal to the project but necessarily become the default for all developers who approach the language, both in terms of the documentation they see and in terms of the default formatting applied to their code. As Swift expands its support for more and more tooling, it would be healthy for the community to have some input into that style. But if the community rejects that approach, it does not change the fact that these tools will have to default to some style, and once standardized internally, it will be for all intents and purposes the "official" style.

11 Likes
(Boris Triebel) #170

If Apple and or the Swift Core Team wants to do that it surely would be a valuable reference and a proof of concept. Until that is done we should put this here on hold.

3 Likes
(Xiaodi Wu) #171

So you support "that" but not "this here"? What is the distinction? I can see none other than the degree of community involvement.

2 Likes
(Tino) #172

When not even a relatively small subset of developers (the different teams working together at Apple) can agree on a common style, how can we expect a much bigger and more diverse group to do so?

7 Likes
(Cory Benfield) #173

I want to address these two points specifically, because I have been through this dance before in the Python community.

First, to establish common ground: @allevato is undoubtedly correct that any out-of-the-box solution to a problem is of value for new users learning a language and new developers. The lower the bar for getting access to a tool, the less cognitive load it imposes on new developers, and thus the better the adoption rate.

The problem I have with this argument is that it applies to literally everything about a language. Followed to its logical conclusion you end up with a language like Python that has a batteries-included standard library which includes, amongst other things, the following modules

  • statistics
  • both pathlib and os.path
  • macpath, for manipulating MacOS 9 paths, finally deprecated as of Python 3.7
  • pickle, implementing 5 versions of object serialisation
  • shelve and marshal, also implementing object serialisation for other use cases
  • sqlite3
  • Support for 5 archive or compression formats, including some that appear to be redundant but have non-overlapping API surfaces
  • curses
  • 3 async frameworks: asyncio, asyncore, and asynchat
  • mailbox, support for handling mailbox files in "various formats"
  • both an HTML and an XML parser
  • a giant bucket of network protocols: HTTP, FTP, POP, IMAP, NNTP, SMTP, telnet, and XMLRPC.
  • HTTP and SMTP servers that can run on the command line
  • sunau for Sun AU files
  • Tcl and Tk bindings

Why do I mention this? Because at one stage or another someone used a similar argument: having this available in the standard distribution makes it easier for users to find it. And they were right!

The problem is that once something is in the standard toolchain for distribution it becomes very difficult to remove it again. Users build up reliance on having the tool or interface present in the toolchain, and while that may seem reasonable in the glow of the original implementation, several years later there is a risk of looking back and finding that in fact we regret the approach that we took.

While we're here, the other downside to this "shove stuff into the distribution" approach is that it has a tendency to disincentivise development of alternatives. This gets particularly troublesome in areas where rapid transition can occur: the builtin Python ssl module has been a limiting factor for a large number of Python applications for a long time, and there is essentially no good alternative available in that language. The faster TLS changes, the worse this problem gets.

On top of that, if the team maintaining the tool fade away without appropriate replacement, the tool tends to begin to fall into disrepair and fall behind the state of the art, at which point it becomes a problem. Consider http.client. Python has a fantastic third-party HTTP client that is so good that the Python http.client documentation literally has a warning at the top that links out to that third-party module. But users who are just reaching for the included batteries end up using the more painful and limiting tool, instead of the one that could most empower them.

What I'm trying to say is that if the main reason to put a formatter into the standard distribution is to make it easier to find it, then I think we'd better serve this community by finding ways to make it easier to get tools like this. Put another way, let's not be batteries-included: instead, let's find a way to make it easier to obtain batteries. Why is downloading formatters and linters hard for users? How can we make it easier? These are questions worth addressing.

In my view, Swift should do the minimal amount possible to make the language useful and vital, and to establish common currency data types where it is important for the community to standardise around certain types or protocols. I'd rather see the language enable innovative tools than to be the source of those tools.

20 Likes
(Pierpaolo Frasa) #174

Why would you think so? The German spelling reform of 1996 turned out to be a spectacular shitshow, with a lot of people questioning the reasoning behind many of the proposals. This topic ended up dominating the media for years and led to several authors and publishers boycotting at least parts of the reforms and implementing their own house styles. For example, many people had (rightly or wrongly) been complaining that the spelling reform was diluting semantic differences (e.g. groß schreiben ("write in big letters") and großschreiben ("write in uppercase") which would have ended being written the same way). The whole thing was quite vicious and if my recollection is in any way close to correct it seems that a full escalation was only avoided by adding amendment after amendment to the reform (the last major one from 2006), a lot of them basically saying something like "you can now legally write it both in the old way or in the new way", just to keep everyone happy. In fact, I think this one very good example for why such a bikeshedding discussion ends up with very real negative consequences.

2 Likes
(Pierpaolo Frasa) #175

Fully agreed.

(Goffredo Marocchi) #176

I do also feel that we are dedicating lots of smart minds to tackle the wrong problem / answer the wrong question.

1 Like
(Tino) #177

As much as I hate to ping others: If the core team is in charge at that point, I hope @tkremenek can answer some questions I consider crucial if this endeavor shouldn't end as a blind flight…

  • What exactly would happen if SE-0250 is accepted?
  • Would there be some sort of deadline for the subsequent proposals that have been promised?
  • Who would be "allowed" to suggest rules? Will there be additional restrictions, or shall the community be involved as with regular proposals?
1 Like
(Simon Evans) #178

I agree strongly with @lukasa's view that we shouldn't bundle anymore tooling into the standard distribution.

It seems that the bigger problem on Linux is that Swift is distributed as just one big tar.gz and if it used packages on Ubuntu then a formatter could be installed with a simple apt-get install swift-format, the same way it is installed on macOS using Homebrew. Apple could distribute a tool in that 'Xcode command line tools' package that always seems to get installed after every Xcode install.

As to using a specific formatter, wouldn't it be possible to use a fixed set of command options and then invoke $SWIFT_FORMAT_TOOL --using-config=... and then users could adopt any tool they wanted as long as it understood a basic set of command args (eg how Clang and gcc both understand the same basic options)? That might solve the problem of having a 'blessed' tool that becames unmaintained.

1 Like
(Rick M) #179

Just want to add my view that any Swift formatting tools should be highly configurable. I have a particular formatting that I use consistently, but it differs from most people's. That doesn't make it invalid. Without configurability, it won't be as widely adopted.

1 Like
(Jeremy David Giesbrecht) #180

That very sentence admits that there had been a previous series of official standards since the orthographic conference of 1901. The orthographic reform of 1996 attempted to change an existing standard that everyone was already accustomed to, so it ran into heavy opposition. (It still largely succeeded; the house styles you mention are far closer to the new orthography than they are to the old.) The original conference of 1901—which went from no standard to a standard like this proposal—saw basically no resistance whatsoever. In fact it was so well received that for decades to follow the overwhelming majority believed an even stricter standard with less tolerated variation was the obvious next step.

It is not a standard library API; no compiled application or even compilation process would depend on it. It has a great deal of freedom to change over time. It would even be easy to drop entirely if it were to somehow become desirable to do so.

Python’s team does not use http.client constantly while developing Python. This tool would be used by the Swift team in day‐to‐day development. I cannot imagine it falling behind and becoming cumbersome to work with when its primary users are also its developers.

1 Like
(Pierpaolo Frasa) #181

Obviously, 1996 and 1901 were vastly different situations (for example, a lot more people were literate in 1996) and also, for all the comparisons that keep being made, programming languages and natural languages are still significantly different. But my point wasn't about specifics of any historical situation, only that standardisation wars can (don't have to, but can) have a very real and devastating effect on "linguistic" communities and that I don't know why this proposal would be less controversial in any language other than English (except for the fact that the audience would be smaller).

(Pierpaolo Frasa) #182

Like XCode+SPM? *cough cough

4 Likes
(Cory Benfield) #183

That's just not accurate. Any tool that can reliably be considered "part of Swift" is something that should be maintained appropriately, unless the proposal is to declare the entire formatter's API to be unstable. And, yes, tools have APIs: they have inputs (command lines, any processing they may do on stdin), outputs (textual on stdout/stderr), and side effects. They are an API like any other.

Of course, part of the goal of shipping a tool like this is that users will use it, and a very common way to use such a tool is as part of a CI pipeline. Changes to the tool that break previous usage will break CI pipelines upon upgrade, and so need to be managed just the same as managing standard library APIs.

Unless I have misunderstood the proposal, its primary users will not be its developers. Its developers will be a subset of its users, and have explicitly suggested that they will not be the most important ones. In particular, note that it does not appear to be proposed that the Swift core team take ownership of swift-format: instead, the proposal seems to be that @allevato's team continue to be primary owners, and to collaborate with the Swift core team.

In the event that, hypothetically, @allevato's entire team went away, it is not necessarily the case that swift-format would continue to be well-maintained by the Swift core team picking up the slack. The Swift community would need to resource the project accordingly, and it is not reasonable to assume that the Swift core team has the resources to maintain such a project.

This is not a hypothetical problem: it is exactly what has happened to the various parts of the Python toolchain that have grown warts over the years. If something gets into the standard distribution, getting it out or making breaking changes to it is slow and time consuming. It behooves us to be extremely conservative about what we propose to add to that distribution.

Again, my proposal is that erring on the side of distributing less, and attempting to solve the problem of how to discover and obtain the tools we need, is the better long term solution. Sadly, it's a solution that is less appealing to most of us, because it's fundamentally not a technical solution, but more about community and documentation efforts.

9 Likes