Skip to content

Instantly share code, notes, and snippets.

@mdparker
Last active October 16, 2017 21:19
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save mdparker/ab61a1309752905cf93acb2653c50beb to your computer and use it in GitHub Desktop.
Save mdparker/ab61a1309752905cf93acb2653c50beb to your computer and use it in GitHub Desktop.
Semantic Versioning for DMD

Use Semantic Vesioning for DMD Releases

Field Value
DIP: (number/id)
RC# 0
Author: (your name and contact data)
Implementation: (links to implementation PR if any)
Status: Will be set by the DIP manager (e.g. "Approved" or "Rejected")

Abstract

A proposal to stop using the 2.0XX.X format for DMD releases and begin using Semantic Versioning.

Links

The Semantic Versioning specification

Rationale

Semantic Versioning (SemVer) has been adopted by numerous software projects around the world. It is a standard with which many developers have become familiar. In contrast, the versioning format used for DMD releases, while not unique, is much less common. It can be confusing to developers who have expectations, thanks to SemVer, about the meaning of each segment of the version number triplet.

In terms of format, SemVer prohibits the use of a leading 0 on any portion of the version triplet, but the middle segment in the DMD version has a leading 0. In terms of behavior, SemVer specifies that the major version should be incremented when a new release of the software introduces changes that are incompatible with previous releases and the minor version incremented otherwise. Currently, the major DMD version is effectively coupled to the language version. Once the 1.0.0 version of DMD was released, the first number was never incremented until development began on a new version of the language (D2). Each "major" release increments the middle number in the triplet, even when the release includes breaking changes. This contradicts SemVer standards and defies the expectations of potential users.

While this is not an issue that has often arisen in the D community forums, it has been brought to the attention of the language authors by software development shops interested in D, but hesitant to use it. It is not cited as the primary reason that these shops are reluctant to adopt D, but as a contribution to the overall impression that the D development community does not follow industry standards. Among the criticisms in this same vein, the complaint about the DMD versioning scheme is the most easily, and painlessly, resolvable.

Description

Someone more knowlegeable than I will have to detail the potential changes in the compiler/runtime/Phobos, if any

Four potential paths are proposed to approach the new versioning scheme. Assuming the first version of DMD to be affected by this is 2.075.0 (for demonstrative purposes):

  1. Simply drop the leading 0 in the middle number, but continue forward with the traditional approach to incrementing the version number. In other words, 2.075.0 would become 2.75.0, the first incremental release 2.75.1, and the next major release 2.76.0. This conforms to the SemVer format, which prohibits leading zeros on each segment of the triplet, while violating the SemVer guidlines for incremementing the version number. This could be an acceptable compromise if it is deemed important to keep the major version of DMD coupled to the language version.

  2. Since the middle number has always been treated as the major version anyway, use it as such in the conversion to the SemVer format. For example, 2.075.0 would instead become 75.0.0. Each major DMD release would then increment the major version if there are breaking changes (76.0.0) and the minor version if not (75.1.0). Incremental releases would increment the patch version. This conforms both to the SemVer format and the guidelines for incrementing the version. It also decouples the DMD version from the language version. Additionally, it has the benefit of clearly showing which of the previous releases preceded it -- 75.0.0 follows 2.074.

  3. Conform to the SemVer format and the guidelines for incrementing the version number as in option 2, but brand the first conformant release as 3.0.0. Rather than showing a clear transition from the last release to use the old format, this option establishes a clean break. An argument can be made that jumping from a major version of 2 to 75 is jarring, while starting with 3.0.0 is more natural.

  4. As option 3, but use version 2.8.0. An argument can be made that if there are breaking changes in this release, then it breaks SemVer by keeping a major version of 2. The counter argument is that the previous release did not follow Semantic Versioning, so it doesn't matter. The next major release can be either 2.9.0 or 3.0.0. This, like option 2, shows a clear succession from the previous release (7x => 8) and allows for a smoother transition than option 3.

yadda yadda yadda

Breaking changes / deprecation process

Tooling? Consider DVM. How will its parsing of the release archive filenames be affected? What about code that tests __VERSION__? I don't see that any of the proposed options would break that, but am I missing something? Anything else?

Examples

Copyright & License

Copyright (c) 2017 by the D Language Foundation

Licensed under Creative Commons Zero 1.0

Review

@MartinNowak
Copy link

@mdparker use of static if (__VERSION__ < 2075) is somewhat idiomatic, so mapping whatever version scheme we choose to an integer mapping that is bigger would help.

@MartinNowak
Copy link

I'm against option 1 as it's just changing the version scheme without actually implementing semver, no point in switching to a different custom versioning scheme.
Option 3 would be my favourite if we also agree to commit to strict API stability for major versions (no removals/deprecations, only additions). That would prolly mean one major version every 6 or 12 month or so and a few minor versions in between.

@jacob-carlborg
Copy link

@mdparker For DVM, as long as the filename of the release archives still use the same naming scheme it should work without requiring any changes.

@MartinNowak
Copy link

BTW, we should rather start with D2 4.0.0 to avoid any confusion with D2 -> D3.

@PetarKirov
Copy link

PetarKirov commented Oct 16, 2017

I'm in favor of Option 4 as it has the benefit of resembling a minor (in SemVer speak) update over 2.7.x (actually 2.07X.X) and doesn't look as controversial as 3.0.0 (though with SemVer we would eventually need to pass through that phycological "barrier").
I would expect __VERSION__ to look like 2800 or 3000, so it should "just work" with code written with the current versioning scheme in mind.

One big open question that remains is whether the dmd version would continue having the meaning of release X of the language + dmd + druntime + phobos combination. dmd is obviously coupled with druntime, however one may imagine phobos as dub package which is compatible with a range of dmd versions. In particular, with the current versioning model, in one release phobos may introduce breaking changes (e.g. removing a deprecated function or module) while dmd having nothing more than internal refactoring changes.
Would it better to ship this as a major phobos release coupled with a minor dmd release in the SemVer world?

Also there's the question whether we decouple the language spec from the dmd language implementation.

@MartinNowak
Copy link

I'm in favor of Option 4 as it has the benefit of resembling a minor (in SemVer speak) update over 2.7.x (actually 2.07X.X) and doesn't look as controversial as 3.0.0 (though with SemVer we would eventually need to pass through that phycological "barrier").
I would expect VERSION to look like 2800 or 3000, so it should "just work" with code written with the current versioning scheme in mind.

Well, the key question here is. Do we do semver, or are we just pretending. At the moment we're doing a major update with every release 2.xxx.0 (every 2 month), and a minor update for point releases (2.077.x). So really the next major versions would be 3.0.0 and 4.0.0.
This only seems reasonable if we divert incompatible changes (removals, new errors & maybe deprecations) into a slower release cycle, say every 6 or 12 month, and keep any other compiler change fully backwards compatible.

In the sense of options 4, we could just use 4 components (2.7.7.0, 2.7.8.0) mapped to 7.7.0 and 7.8.0 in semver and git. Would ease transition psychologically. But it's only numbers and we could jump straight to 7.7.0, avoiding tooling exceptions and having to explain 2.7.8.0. In fact I like 7.7.0 quite a lot.

Yes, obviously __VERSION__ must be strictly increasing.

One big open question that remains is whether the dmd version would continue having the meaning of release X of the language + dmd + druntime + phobos combination. dmd is obviously coupled with druntime, however one may imagine phobos as dub package which is compatible with a range of dmd versions. In particular, with the current versioning model, in one release phobos may introduce breaking changes (e.g. removing a deprecated function or module) while dmd having nothing more than internal refactoring changes.
Would it better to ship this as a major phobos release coupled with a minor dmd release in the SemVer world?

Yes, whether to uncouple phobos from dmd releases remains a topic, but it also requires quite a lot of discussion and thought. From the current perspective it seems better to stabilize dmd and phobos. Also phobos already uses a long interval for the deprecation process, it would just mean that deprecations can only be added to the edge/future branch, not at random minor releases from stable.

Whether or not features should be added for minor releases remains a difficult trade-off, but I'd think this would easily get sorted intuitively, e.g. too big a feature for stable, let's put it in edge/future. Now that GH allows to change base branches of PRs, it should be much less of an issue.

But again this needs quite some discussion between contributors and stakeholders to arrive at an agreeable consensus.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment