Semantic Versioning in Swift

Sorry, I wasn’t clear. I don’t mean what changes are worth a minor version bump. I mean literally, for a library at any level of the stack, what can be done in a minor version bump?

I mean literally, for a library at any level of the stack, what can be done in a minor version bump?

I'm not sure I understand the question. Anything which doesn't break backwards compatibility. I.e. would cause any other module fail to build properly.
In Swift that seems to be: not much within the language, but only in proper extension points. (very much like C++)

(And by "minor version bump" I only refer to SemVer here. Other versioning schemes can come up with different rules and e.g. restrict consumers to a language subset.)

I don’t have a good mental picture of what that looks like. Do you think you could sketch out what such an interface would look like and how you would extend it?

I already gave you 4 examples of such systems, what else do you need? (you asked about "any level of the stack", they are not useful in the NIO context, IMO).

Which is why I don’t follow a strict SemVer for my libraries. Otherwise I’d be up to major version 112.

IMO strict SemVer is very hard to follow, since it severely restricts what you can do. I’m not objecting to the premise behind that strictness. I just prefer having more flexibility with what I can do.

1 Like

I'm not sure why it isn't possible to respect SemVer? There are several things one can do in a minor, including:

  • Any rearranging of internal symbols
  • Adding new classes or structs
  • Adding method to structs and to existing public (not open) classes
  • Adding methods to existing protocols, as long as a default implementation is also provided
  • Making classes conform to new internal protocols
  • Deprecating (without removing; with @available(… deprecated…) or similar*) existing functionality and replacing it with new methods

etc.

*: Pitches are welcome for deprecation schemes that do not involve OS versions.

I see no problem with a major version 112. All that tells me is that you probably release often (good!), and 112 of those releases required a little work to upgrade from a previous release.

If Swift is designed such that many releases are breaking changes, then so be it that we'll just have high major version numbers. The versioning scheme isn't going to change the fact that a breaking change is a breaking change.

Technically if you follow strict SemVer, adding just about anything in Swift could cause a compilation failure somewhere down the line. Which means most changes require a major bump.

I'm not sure this holds; as it is, Swift developers face continuous additions to their underlying libraries (e.g. in macOS/iOS etc. releases) and so far this has had little to no source compatibility breakage, especially since Swift introduced source compatibility based on language versions (e.g. Swift 3 mode). So, I'm confused.

What do you mean by that precisely?

It comes from Swift’s ability to add extensions that can add protocol conformances and methods. While I think the probability that collisions happen is low, it still means that if you follow strict SemVer, adding these kinds of things would require a major bump.

Yeah, strongly agreed — I argue for that one bit precisely above (I believe adding public protocol conformances to public classes is a semver major break).

There are a few things that are less obvious — for example, adding new public or open methods to open classes is a potential source break (because a subclass may be introducing them for their own use). But in general I would argue that the leeway one has in minors, with a little care in design, can be sufficient to introduce significant changes.