Move `PackageDescription.Version` into the standard library. Add Decodable conformance

This is a fairly simple proposal.

I believe that the Version struct from the PackageDescription library should be moved into the swift standard library, and Codable conformance should be added.

Reasoning

Apps often need a way of checking if they are out of date. Usually this is used to let users know that there is a new version of the app available.
Nobody is perfect, and sometimes breaking bugs slip into production code. When this happens, it's important to get users off of the broken version as quickly as possible.

Generally, this is achieved by:

  1. fetching the CFBundleShortVersionString from the info.plist,

  2. fetching the current production version from: https://itunes.apple.com/lookup?bundleId=appBundleId

  3. comparing the on-device version with the current production version from the App Store and letting users know an update is available if the production version > on-device version.

To make this process cleaner, its also common to make a custom Version class with the following characteristics:

  1. has a Major, Minor, Patch property (Int)

  2. can be initialized from a string, or series of Ints

  3. Conforms to Equatable, Comparable, Codable to allow comparisons and decoding the version number from AppStore response.

Unsurprisingly, this functionality already exists and is already heavily in use with the swift package manager.

However, if you try to import PackageDescription into your app targets to use the Version struct, you are greeted with "Module 'PackageDescription' not found"

The only thing the current implementation is missing is Decodable conformance.

I think that having this Version struct available in the Swift standard library, with Codable conformance would be a very nice quality-of-life addition to the language.

2 Likes

I’m not sure the standard library is the place for this but I do agree that it would be nice to have this battle tested code in a package that could be imported easily.

5 Likes

Just as a side-note here, TSC has a Version type: swift-tools-support-core/Version.swift at main · apple/swift-tools-support-core · GitHub

2 Likes

Sorry, first time bringing up a proposal. Still learning how things work around here.

Would it make more sense for it to be in Foundation? It’s not the type of thing that will be used everywhere in a codebase, but it’s definitely a common enough use case in many apps.

I think having a lightweight and correct semver type with basic operations in the standard library makes a lot of sense.

When we added Unicode.Scalar.Properties (SE-0211), one of the properties added was age: Unicode.Version, which is a tuple (major: Int, minor: Int) that describes the Unicode version that the code point was introduced in.

I wanted to add a Unicode.supportedVersion property later that would return the version of Unicode currently supported by the system's ICU so you could make runtime decisions about the validity of the information you were getting back ([stdlib] Add supportedVersion property to Unicode namespace. by allevato · Pull Request #18180 · apple/swift · GitHub), and that change would have turned Unicode.Version into a struct instead, but the PR got stalled and we didn't land it before the version with the tuple got locked into a release of Swift.

For source-/ABI-compatibility reasons I imagine we're stuck with the tuple for Unicode.Scalar.Properties.age now, but in general, I think these two use cases plus SwiftPM make a good case for it to be considered to be added as part of the standard library vs. a separate package.

cc: @Michael_Ilseman and @lorentey who mentioned also wanting something like this in comments on the PR above.

7 Likes

If you're talking about a module's version (e.g. checking if an App is out of date, as you suggest), that is something which is entirely absent from Swift today. The language and compiler have no concept of your code being at a particular version.

The only place versions exist is in the package manager - and even then, only for dependencies (your package never has a version) - and even then, they are only used as a naming convention for tags in Git, so it can find the best revision of the dependency to download.

I agree that we need better support for versioning (every module should have a version, you should be able to query them and limit functionality using @available, etc), but it's a much bigger topic than just adding a type to the standard library.

4 Likes

@Karl

I am not specifically looking for a means of handling app updates and checking the apps current version.

Just looking for a standardized class/struct for handling semantic versions. We currently already have it in the PackageDescription library. But that library cannot be imported outside of Package.swift files.

Although, that being said, having some way of handling per-module versioning like you mentioned would be a very nice addition as well.

I see, so you do just want the "currency type" because you're on a Darwin platform, where the Bundle's Info.plist has that information already.

I think we should still think about how this fits across the entire ecosystem. AFAIK there is no requirement that we have Info.plists on linux/windows/android/wasi/whatever, and they may/may not have version information.

1 Like

I agree with Alejandro, that this is better suited as a package we can import rather than the standard library.

2 Likes

I'll add that I've also needed to parse and compare semantic version strings on servers as well as scripts that help manage releases of software. In these cases, the version being parsed wasn't the binary/package's own version, it was passed to it from some external source.

In many of these cases, I wrote my own limited version parser, and I imagine many others do as well.

IMO, Having a single library that the community uses by some sort of consensus would be beneficial (kind of like the swift-argument-parser).

2 Likes

I agree; something like swift-semantic-version, if written by Apple and hosted on Apple’s GitHub account as a Swift package, would probably gain immediate traction.

3 Likes

A quick check shows at least 5 Swift Semantic version parsing libraries on GitHub, including one that says its derived from the SPM Version.swift code. They have a mix of support for Cocoapods and SPM as dependencies.

Do we need another one?

1 Like