Carbon uses a single versioning scheme across both the language itself and toolchain, including the standard library, compiler, linker, and all development tools released by the main Carbon project.
The scheme conforms to and is closely based on Semantic Versioning (https://semver.org/ -- version 2.0.0):
MAJOR.MINOR.PATCHMAJOR after reaching the
1.0 milestone, and increment MINOR before then.PATCH.MAJOR.MINOR.PATCH-rc.N: The N-th potentially viable candidate for a
release.MAJOR.MINOR.PATCH-0.nightly.YYYY.MM.DD: A nightly incremental
development build on a particular day during development of that
version.MAJOR.MINOR.PATCH-0.dev: An interactive, incremental development build
on a particular day by some developer during development of that
version.See the sections below for the details of each aspect of these versions.
Aligned with SemVer, the major version must increment for any breaking change to the language or any part of the toolchain.
The first increment from 0 to 1 is expected to be based on achieving a desired milestone of feature completeness and quality to declare the language to have reached a stable version.
Subsequent increments are expected to be done with a time-based release strategy. Features (or breaking changes) ready to ship will do so, and others will wait for the next major release. The exact cadence used is future work and should be determined based on discussions with Carbon's users in the ramp up to and after reaching the 1.0 milestone.
However, just because we increment the major version for a major release and can make breaking changes doesn't mean we will or should. Breaking language changes are extraordinarily expensive for users due to the inherent scale of churn they impose. It is tempting to try to make non-breaking releases instead, but our experience with C++ language, compiler, and standard library updates is that truly making no breaking changes is extremely difficult and overly constraining. We expect most releases, especially in the early phases of the language to involve some amount of breaking change and will simply work to make these as cheap to upgrade through and minimal as we can.
At some future point, it is possible that Carbon will become so stable that it makes sense to consider using minor version increments for some releases. If and when this happens, we should revisit our versioning and release policies to establish a predictable and unsurprising structure.
Beyond traditional breaking API changes in either standard library APIs or tool APIs, Carbon also includes breaking changes in the language or toolchain. Language and toolchain breaking changes are any that cause correct, functioning, and non-reflective code to become invalid, rejected, incorrect, or silently change behavior.
Carbon excludes "reflective code" which is in some way detecting the Carbon version, or the presence or absence of features and as a consequence can be "broken" by detecting changes that are correctly designed to otherwise be non-breaking. We don't want adding features to be considered a breaking change and so exclude code that specifically detects such additions.
Carbon also excludes breaking changes to incorrect code unless it was accepted and functioning in some useful, and typically widespread, way despite its bugs.
Currently, Carbon plans to primarily use the minor version increments with a 0 major version to track our progress towards our 1.0 milestone of a feature complete initial language. As a consequence we have defined 0.1 and 0.2 milestones and may define more steps as needed.
Beyond this and in a post-1.0 language world, we expect most significant features to also accompany some small and manageable breaking changes from deprecations. We may choose to revisit this in the future, but our current plan is not to make minor version releases post-1.0 and instead focus on our commitment to making those updates both easy and scalable for language users.
The patch version will increment when the change is fundamentally a bug fix to a previously released version. We expect the vast majority of these to be strictly backwards compatible bug fixes.
Patch releases are expected to be driven by demand, and not necessarily present if unnecessary. However, the exact schedule and process will be determined as part of getting ready for the 1.0 milestone. Before that milestone we don't commit to any particular process or cadence for patch releases as no release before that point should be considered stable.
Note that we still consider restoring the intended "public API" of a release to be a bug fix. When these bug fixes theoretically break new code in a way that would typically require a major version increment, they may be made with merely a patch version increment when they are in fact restoring our intended behavior for that release. However, we take the SemVer guarantees very seriously as these fixes can still be disruptive and so we work to hold a high bar for them:
Beyond the major, minor, and patch versions of an actual release, SemVer provides a foundation for pre-release version management. However, it is a very open-ended foundation with a wide range of possibilities and no particular semantic model provided. Some of this is to support the wide variety of different needs across different projects. It also reflects the fundamentally less crisp and well defined criteria needed for pre-releases.
That said, Carbon should try to have a small and well articulated scheme of pre-release versions to help communicate what these releases do and don't constitute and how they should be interpreted. These are selected to provide a framework that allows pre-release versions to order in a reasonably cohesive way when compared using SemVer.
In descending order, Carbon pre-releases may use:
MAJOR.MINOR.PATCH-rc.NMAJOR.MINOR.PATCH-0.nightly.YYYY.MM.DDMAJOR.MINOR.PATCH-0.devWe expand on each of these below to provide criteria and details.
MAJOR.MINOR.PATCH-rc.NWe create release candidate or "rc" pre-releases when we believe that version to be complete and ready to release and want to collect feedback. There should not be interesting or significant gaps, even known ones, from the intended release. The expectation should always be that unless some feedback arrives to the contrary, the release candidate could simply become the release.
For each pre-release category, we always suffix with a sequential count N of
the pre-releases at that version. We must start with a .0 in order to have
subsequent iterations of the same version and category of pre-release to sort
after the first.
MAJOR.MINOR.PATCH-0.{nightly,dev}.NThese are versions that are not in any way associated with the actual expected release, but are periodically produced as an incremental tracking of development progress. Because they are not expected to be part of qualifying a specific release, they're not defined by any particular criteria of completeness or readiness. In practice, these will occur at every stage between one release and the next.
These are automated incremental development versions built each night when the automated testing passes. There is no attempt to provide any higher quality bar or refinement than whatever was in the tree at the time the automation runs, and whatever automated tests are present pass.
It is important to emphasize that the primary use case of these pre-release versions is not to evaluate a potential release but for the developers and contributors to Carbon itself to track incremental development progress. That development-oriented goal drives how they are built and what they do and don't provide.
Mechanically, we prefix the nightly pre-release version component with a 0
component to ensure these versions sort before any and all release qualification
pre-release versions. We also add a date-derived suffix to provide a rough
chronological ordering of nightly builds with otherwise identical versions.
During development, interactive builds of Carbon need to be versioned in an
unambiguous way, and we do that with the dev pre-release version. Much like
nightly versions, these are only produced as artifacts of development activities
and are never part of any actual release process. These versions are further not
built expected to be automated or necessarily repeatable. They may contain
in-flight edits and all manner of other variations.
Mechanically, we prefix the dev pre-release version component with 0 in the
same way as nightly is prefixed to ensure effective ordering. We don't add any
additional information to keep the mechanics of development builds simple -- for
example, there is no easy way to extract the date of the build. The exact
timestamp of the build may be available but doesn't participate for simplicity
and minimizing cache impact.