Swift Package Naming Conventions

Hi,

I spent some time asking package maintainers and searching these forums, but I didn't find a satisfactory answer to my question: are there any package naming conventions/guidelines for SPM packages?

Some background:

As someone who values consistency, I've been paying closer attention to how package authors name their packages in the manifest. I've looked at official packages, SSWG packages, iOS/macOS packages, etc. To clarify, I am referring to the name property of the Package, not products or targets.

Here's what I found:

  • Some packages use dash-case (aka kebab-case). Notable examples: swift-driver, swift-numerics, swift-log, swift-crypto, and swift-nio. Other that fall into this group are SSWG packages and the new standard library preview packages.
  • Some packages use CamelCase. Notable examples: SwiftPM itself, SourceKitLSP, and SwiftSyntax. Almost all iOS/macOS packages follow this convention.

I understand if this detail is considered trivial or irrelevant, especially since package names play a much lesser role compared to other package managers such as npm (link). It is also worth noting that this situation is not unique to SPM and can be found in other ecosystems, such as Rust, where snake_cased and dash-cased crate names are both widely used (although the latter is gaining more momentum).

At the same time, I think that with the eventual introduction of a package registry (GitHub's or otherwise), these naming inconsistencies are going to surface to the end user much more than they do today.

Is the absence of SPM package naming guidelines by design? If so, can someone shed some light on this?
If it is not, would it make sense to pursue converging towards one convention? Could it happen organically or should it be enforced on the manifest level?

14 Likes

Good question! Thanks for opening this thread.

IMHO I prefer CamelCase. That's what the modules are usually doing, so you can import CamelCase, and I prefer when a package name is the same as the module name.

EDIT: My comment was referring to this SE-0226: Package Manager Target Based Dependency Resolution but reading it again I'm not sure it applies. Sorry for that.

3 Likes

I appreciate these threads popping up!

In general I follow the pattern established by swift-nio, swift-numerics, etc, but I'm beginning to agree with @Alejandro_Martinez that the Package name should be PascalCase and match the first/primary product, to be closer to what the first expected import statement would be.

I also realize that I'm not entirely consistent:

  • Package: redi-stack
    Repo: swift-redi-stack
    Primary Product: RediStack
  • Package: swift-currency
    Repo: swift-currency
    Primary Product: Currency

I think the primary goal of pattern I followed was to associate strongly between the git URL and the project name. But as you say, it'll become more apparent at how redundant or "off" this will look as soon as a Swift Package Index is off the ground.

Is the absence of SPM package naming guidelines by design?

The fact that we need a unique package name, git URL, and target / product names is by design and influenced by technical limitations (that existed at least initially).

A lot of SPM's design is also geared towards decentralization and being unopinionated where it doesn't matter - such as how to actually name your project or structure it.

If it is not, would it make sense to pursue converging towards one convention?

Of course! Having established conventions makes it easier for someone to jump into an ecosystem, as they understand how to contribute or even search for what they need.

Could it happen organically or should it be enforced on the manifest level?

I think it should not be enforced at the manifest level. This is highly a preference thing, and way less a technical thing. Our build and package tools don't care about what we name our projects - they could just be SHA hashes - and everything would continue to work the same.

2 Likes

I think we should follow the style used by the vast majority of packages:

  • Repo: https://example.com/user/ExampleKit.git
  • Package: ExampleKit
  • Product: ExampleKit

I understand why Apple uses the other approach to namespace their packages, but I think it would be a lot better to have them use this style, ie:

  • https://github.com/swift/Foundation.git
  • https://github.com/swift/XCTest.git
  • https://github.com/swift/NIO.git
  • https://github.com/swift/Crypto.git
  • https://github.com/swift/Logging.git
    ...
7 Likes

Also, something that is becoming a factor with the introduction of the new package dependency resolution stuff in SwiftPM 5.2, is that a client package needs to declare the name of a product dependency explicitly unless it matches the last path component of the URL. Whereas before the URL didn't really matter, now choosing it to match the product name brings a functional convenience for users of the package.

3 Likes

I haven't considered the URL when I initially posted this, but there are other aspects to account for when it comes to that. Since many packages are composed of 2 words or more, dash-case makes for better URL readability, especially with URL case-insensitivity being a factor. Not the main concern, but one to keep in mind.

That being said, I am starting to believe that the pros of using CamelCase across the board, including the URL, outweigh the cons.

Just to be clear: UpperCamelCase and lowerCamelCase. Swift classes use the former and variables use the latter.

1 Like

I would say that it is a popular convention, but, not a requirement. The compiler accepts any set of cases.

FYI: Only the domain portion of a URL is caseā€insensitive; the path is not. (But if you get lucky and the server happens to have its file system configured to be caseā€insensitive, you may not notice the difference.)

1 Like

FYI: Only the domain portion of a URL is caseā€insensitive; the path is not. (But if you get lucky and the server happens to have its file system configured to be caseā€insensitive, you may not notice the difference.)

That's correct. I was looking at GitHub when I wrote that, and their repo URLs are case-insensitive based on my own tests.

Would it be non-Swift-idiomatic or out of scope to consider having SwiftPM consider alternate casing/word-breaking package names as the same name? I.E. To grab or interact with the SwiftSyntax package, a user could type "SwiftSyntax", "swiftSyntax", "swift-syntax", "swift_syntax", etc.

Implementation-wise, we'd need 2 things: 1. a simple spec for how word breaks are determined (for which there's plenty of precedence in the Obj-C & Swift docs and community), and 2. a way to check for similar package names (internally normalizing all names to a standard form, say hyphen-separated words, and then doing checks and comparisons only on normalized names seems easy and efficient enough).

What about 3-letters prefixes for modules, like we do it in Objective-C world? Should SPM module be named ABCCoolThing and, e.g. contain ABCCoolThing class, or module should be named CoolThing and class be ABCCoolThing or even class should be CoolThing. What about names collisions?

IMO, the best way to avoid name collisions for modules is to add structure to the name. We could use a reverse URL structure like Java, allowing for simple vendor prefixes which may be omitted if the desired module is unambiguous.