There are two simple rules to Unary Versioning.
First, all numbers are given in unary, also called Base-1.
Second, given a version number MAJOR.MINOR.PATCH, increment the:
Additional labels for pre-release and build metadata are available as extensions to the MAJOR.MINOR.PATCH format.
In the world of software management there exists a dreaded place called “number parsing hell.” The bigger your system grows and the more packages you integrate into your software, the more likely you are to find yourself, one day, in this pit of despair.
In large distributed systems with heterogeneous technologies, there is a large variety of tools and language capabilities commonly used. Managing package and software release versions took a large step forwards with the introduction of Semantic Versioning. However, the Semantic Versioning approach has a fatal flaw: the representation of numeric values as human-readable strings. A human-readable number must be converted into a machine-readable number before a dependency management can hope to correctly resolve the dependencies for a project. Many mainstream development languages have number-parsing capabilities, but some do not. Even those that do will frequently require complicated manual setup and preparation.
As a solution to this problem, we propose a simple extension of the rules of semantic versioning, which minimizes the required capabilities of any software environment that needs to handle version numbers intelligently and with minimal effort. As a first step, follow the versioning recommendations set out by Semantic Versioning. However, when encoding version numbers, there is one extra rule to follow:
When writing down your version numbers, always use Base-1 instead of Base-10. For example, if you conceive of a version as being 1.2.3, write it down as 1.11.111. This has two benefits:
split
and a len
function are required to assess
the version number. No complicated parseInt
is needed.We call this system “Unary Versioning.” As outlined above, this scheme is strictly easier and equally as expressive as semantic versioning. Due to the widespread adoption of Semantic Versioning and the undeniable, objective improvement that Unary Versioning brings, we expect this scheme to become the dominant software versioning scheme in the Open Source community quickly.
At this point, you are obviously convinced of the benefits of Unary Versioning, and find yourself saddened by the fact that your projects are already using Semantic Versioning.
Fear not, for migration is very easy. Quite simply, the next time you increment your software version, simply apply the Unary Version strategy to all numbers which have changed, making sure to choose your new version number such that the Base-10 reading of your new unary version number exceeds the previous version number. For example, when updating the minor version from 1.15.3, declare the next version as 1.111.. Note the empty string for the patch number, which is consistent with standard Base-1 notation.
The key words “MUST”, “MUST NOT”, “REQUIRED”, “SHALL”, “SHALL NOT”, “SHOULD”, “SHOULD NOT”, “RECOMMENDED”, “MAY”, and “OPTIONAL” in this document are to be interpreted as described in RFC 2119.
Precedence refers to how versions are compared to each other when ordered.
Precedence is determined by the first difference when comparing each of these identifiers from left to right as follows: Major, minor, and patch versions are always compared numerically, or, equivalently, by length.
Example: 1.. < 11.. < 11.1. < 11.1.1.
When major, minor, and patch are equal, a pre-release version has lower precedence than a normal version:
Example: 1..-11111 < 1…
Precedence for two pre-release versions with the same major, minor, and patch version MUST be determined by comparing each dot separated identifier from left to right until a difference is found as follows:
Example: 1..-11111 < 1..-11111.1 < 1..-11111.1111 < 1..-1111 < 1..-1111.1 < 1..-11.11 < 1…
<valid semver> ::= <version core>
| <version core> "-" <pre-release>
| <version core> "+" <build>
| <version core> "-" <pre-release> "+" <build>
<version core> ::= <major> "." <minor> "." <patch>
<major> ::= <numeric identifier>
<minor> ::= <numeric identifier>
<patch> ::= <numeric identifier>
<pre-release> ::= <dot-separated pre-release identifiers>
<dot-separated pre-release identifiers> ::= <pre-release identifier>
| <pre-release identifier> "." <dot-separated pre-release identifiers>
<build> ::= <dot-separated build identifiers>
<dot-separated build identifiers> ::= <build identifier>
| <build identifier> "." <dot-separated build identifiers>
<pre-release identifier> ::= <nonnumeric identifier>
| <numeric identifier>
<build identifier> ::= <nonnumeric identifier>
| <digits>
<nonnumeric identifier> ::= <non-digit>
| <non-digit> <identifier characters>
| <identifier characters> <non-digit>
| <identifier characters> <non-digit> <identifier characters>
<numeric identifier> ::= ""
| <digits>
<identifier characters> ::= <identifier character>
| <identifier character> <identifier characters>
<identifier character> ::= <digit>
| <non-digit>
<non-digit> ::= "-"
<digits> ::= <digit>
| <digit> <digits>
<digit> ::= "1"
As specified above, Unary Versioning encompasses all the benefits of Semantic Versioning while requiring minimal computational capability to use these benefits from any software system that would like to do so.
There are literally no drawbacks of any kind in using unary versioning over standard Semantic Versioning.
The simplest thing to do is start your initial development release at .1. and then increment the minor version for each subsequent release.
If your software is being used in production, it should probably already be 1… If you have a stable API on which users have come to depend, you should be 1… If you’re worrying a lot about backwards compatibility, you should probably already be 1…
Major version zero is all about rapid development. If you’re changing the API every day you should either still be in version .y.z or on a separate development branch working on the next major version.
This is a question of responsible development and foresight. Incompatible changes should not be introduced lightly to software that has a lot of dependent code. The cost that must be incurred to upgrade can be significant. Having to bump major versions to release incompatible changes means you’ll think through the impact of your changes, and evaluate the cost/benefit ratio involved.
It is your responsibility as a professional developer to properly document software that is intended for use by others. Managing software complexity is a hugely important part of keeping a project efficient, and that’s hard to do if nobody knows how to use your software, or what methods are safe to call. In the long run, Semantic Versioning, and the insistence on a well defined public API can keep everyone and everything running smoothly.
As soon as you realize that you’ve broken the Semantic Versioning spec, fix the problem and release a new minor version that corrects the problem and restores backwards compatibility. Even under this circumstance, it is unacceptable to modify versioned releases. If it’s appropriate, document the offending version and inform your users of the problem so that they are aware of the offending version.
That would be considered compatible since it does not affect the public API. Software that explicitly depends on the same dependencies as your package should have their own dependency specifications and the author will notice any conflicts. Determining whether the change is a patch level or minor level modification depends on whether you updated your dependencies in order to fix a bug or introduce new functionality. We would usually expect additional code for the latter instance, in which case it’s obviously a minor level increment.
Use your best judgment. If you have a huge audience that will be drastically impacted by changing the behavior back to what the public API intended, then it may be best to perform a major version release, even though the fix could strictly be considered a patch release. Remember, Semantic Versioning is all about conveying meaning by how the version number changes. If these changes are important to your users, use the version number to inform them.
Deprecating existing functionality is a normal part of software development and is often required to make forward progress. When you deprecate part of your public API, you should do two things: (1) update your documentation to let users know about the change, (11) issue a new minor release with the deprecation in place. Before you completely remove the functionality in a new major release there should be at least one minor release that contains the deprecation so that users can smoothly transition to the new API.
No, but use good judgment. A 4095 character version string is probably overkill, for example. Also, specific systems may impose their own limits on the size of the string.
No, “v1.11.111” is not a unary version. However, prefixing a unary version
with a “v” is a common way (in English) to indicate it is a version number.
Abbreviating “version” as “v” is often seen with version control. Example:
git tag v1.11.111 -m "Release version 1.11.111"
, in which case “v1.11.111” is a tag
name and the semantic version is “1.11.111”.
Of course. It was created by Kjeld Schmidt by forking the SemVer website and changing some text.
The Semantic Versioning specification was originally authored by Tom Preston-Werner, inventor of Gravatar and cofounder of GitHub.
The Unary Versioning specification was created as a spoof and is largely a direct copy, largely devoid of meaningful change, other than the repetition of a simple joke significantly beyond the point of it actually being funny.