Version numbers should be boring

In a perfect world, I would never blog about version numbers in Perl.

Version numbers should be boring. No one should have to think about how they specify or check a version number. Perl programming makes things easy, not hard, right?

Unfortunately, version numbers in Perl aren't boring and easy. Instead, they are complicated and confusing. Every Perl programmer needs to understand at least some of this complexity. Otherwise, you can make life difficult for yourself or others without realizing it.

In this article, I'm going to explain what I think are 'good practices' for dealing with version numbers in Perl. I'm going to point out what I think are 'bad practices'. ((N.B., the Perl Best Practices book is wrong)) In the end, I'm going to make some recommendations that I hope people will follow for their own sake and the sake of others who work with their code.

For the impatient, the disinterested or those who just want to follow a recipe, my advice for all modules is this:

our $VERSION = "0.001"; # or "0.001_001" for a dev release
$VERSION = eval $VERSION;

If you already use decimal versions that aren't in the 3-digit decimal format, that's fine, too. It's not worth switching for code you've already published.

If you disagree with me or would like to see alternatives or want to know the ugly details behind this recommendation, then the rest of this article is for you.

Can we skip the history lesson?

It will be helpful to review at least a little history, then we can ignore how we got here and just focus on what to do. There are three big historical accidents worth noting: ((They were actually intentional, but had unforeseen consequences))

Accident #1: Perl expects a module to put its version number in a package variable called $VERSION

The first accident means that a module version number can be anything that can be represented by a Perl scalar: a number, a string, an object, etc. There are no constraints, only conventions. This is a blessing and a curse; it's the main reason why version numbers in Perl aren't boring.

Accident #2: The Perl 5.6 interpreter changed from a 'decimal' version number (5.005_03) to a 'dotted-integer' version number (5.6.0)

The second accident got people thinking that 'version numbers' for modules shouldn't be decimals either. It also introduced a three-digit convention for translating between the two approaches: 5.6.2 is equivalent to 5.006002 and 5.005_03 is equivalent to 5.5.30. Finally, it introduced new syntax for 'v-string' literals of the form 'v1.2.3.4' to help represent dotted-integer version numbers.

A third historical accident was actually an attempt to fix the second:

Accident #3: The Perl 5.10 interpreter made $^V a version object instead of a v-string

Version objects are an attempt to overcome numerous limitations and challenges using v-strings for module version numbers. The UNIVERSAL::VERSION() method also changed, to better accomodate version objects and v-strings.

Here is a very contrived example of the change to VERSION(), where 120, 100, 103 are just the ASCII codes of the letters of my IRC nickname:

$ perl5.8.8 -e '$VERSION=v120.100.103; print main->VERSION'
xdg

$ perl5.10.0 -e '$VERSION=v120.100.103; print main->VERSION'
v120.100.103

The version.pm module provides an interface to version objects and, for older versions of Perl, overrides UNIVERSAL::VERSION() globally to match the behavior of Perl 5.10. The version.pm module is one more thing that keeps version numbers from being as boring as I'd like.

$ perl5.8.8 -Mversion -e '$VERSION=v120.100.103; print main->VERSION'
v120.100.103

Think about the implications of that for a module called 'Foo'. Even if Foo doesn't use version.pm, if version.pm is loaded anywhere then Foo->VERSION acts differently and gives a different value than is in $Foo::VERSION.

Version numbers are for machines, not people

For the most part, version numbers are used to answer just two questions:

  • What version of Module X does Module Y require in order to work properly?
  • Is there a more up-to-date release of Module Z available?

Neither question is one that we, as people, particularly want to waste our time on if a computer can answer the questions for us. That means that version numbers need to be specified in a way that makes it easy for a computer to answer these questions.

Recommendation: Never use alphabetical characters in a version

Don't use '1.20alpha' or '2.34beta2' or '2.00R3'. There are no standard conventions for alphanumerics, and you just make life hard for the machines, which means no help for the humans.

Decimals and dotted-integers

After following the first recommendation and excluding alphabetical characters for module versions, we are left with two numeric conventions, just like Perl itself:

  • decimal numbers
  • dotted-integers (also called dotted-decimals or tuples)

A decimal version is just what it seems: an ordinary number that is either an integer (12) or decimal fraction (12.345). Decimal versions are compared in the ordinary, numerical way.

Dotted-integer versions are vectors of (positive) integers, so called because they are usually shown separated by full-stop characters (12.3.45). Dotted-integer versions are compared by pairwise numerical comparison of the first element of each version, then the second, the third, and so on.

There are two ways to represent dotted-integer versions in Perl:

  • v-strings
  • version objects

I already described v-strings, but you can read more about them in the perldata documentation page. Despite what it says, v-strings are not deprecated. (This warning will be removed in a future version of Perl.)

Version objects are created using the version.pm module. There are several ways to do this. Here is one example (and it must be kept on one line):

use version; our $VERSION = version->new("v1.2.3");

The version.pm documentation has been updated in 0.77 to better explain the options and potential pitfalls creating version objects, so I won't repeat them here.

John Peacock, the author of version.pm, recently suggested that it is probably enough to use version.pm and give a quoted $VERSION string without the need to explictly construct an object, as UNIVERSAL::VERSION will convert it to a version object internally anyway. ((The 'use version;' part isn't even required if the code is limited to Perl 5.10 or later.))

use version; our $VERSION = "v1.2.3";

This approach is new and untested, but may eventually be regarded as the best way to use version.pm.

Three-digit convention

Perl decided upon on a three-digit convention to convert between the older decimal style and the newer dotted-integer style so that older Perls could give a useful error message when checking the Perl version number.

# on Perls before 5.6.0
use 5.6.2; # syntax error
use 5.006002; # Perl version error

The three-digit convention takes each dotted-integer component after the first, pads them with leading zeroes if less than 3 digits, and concatenates them together. To go the other way, the fraction portion of a decimal version is padded with trailing zeroes until the number of characters is a multiple of three, then each group of three digits is turned into an integer.

This convention has a subtle complexity: note that the conversion does not round-trip if a dotted-integer element is greater than 999. This might happen if a version number were constructed from a VCS revision number or a timestamp.

v1.2.34567 -> 1.00234567
1.00234567 -> v1.2.345.670

The introduction of the three-digit convention confused people in two ways: how to convert modules from decimal versions to dotted-integers and how to specify version number limits to use().

Many CPAN modules don't use three-digit decimals, partly because most module boilerplate tools create modules with a two-digit decimal starting version:

$VERSION = "0.01";

These modules usually increment their versions as 0.02, 0.03 and so on. Some authors have been surprised trying to convert their decimal versions into dotted-integers and running afoul of the three-digit convention. In the following example, a naive conversion results in a number that is less than the previous one:

0.01
0.02
0.03
v0.4.0 # WRONG: this is 0.004
v0.40.0 # RIGHT: this is 0.040

The other area of confusion is providing a version number requirement to the use() keyword. With the introduction of v-strings, but prior to Perl 5.10.0, use() internally converts "use Foo v1.2.3" to "use Foo 1.002003". So this works as expected:

# in Foo.pm
our $VERSION = "0.001002";

# in foo.pl
use Foo v0.1.2; # WORKS

However, since Perl recommends specifying "use v5.6.0" as "use 5.006", some people think the same should apply to loading modules with use(). But, prior to Perl 5.10.0 (and the change to UNIVERSAL::VERSION), the inverse case might not work at all! Consider this example:

# in Foo.pm
our $VERSION = v0.1.2;

# in foo.pl
use Foo 0.001002;

On a Perl compiled with support for long doubles, the extra precision in converting with the three-digit convention causes the comparison to fail with this incredibly confusing error message:

$ perl-5.8.9-64bit -e 'use Foo 0.001002'
Foo version 0.001002 required--this is only version 0.001002

Recommendation: always use() in the same form as $VERSION in a module

When $VERSION is a v-string, it should only be requested as a v-string ("use Foo v0.1.2"), except on Perl 5.10 or when using version.pm. There is a corollary:

Recommendation: don't switch version number schemes for a published module

If you do switch, then users won't know in advance the right format to request.

Distribution version numbers

Distributions on CPAN also have version numbers. These are specified as part of the filename. (See a prior article for a formal definition of modules and distributions.)

DAGOLDEN/File-Marker-0.13.tar.gz

Recommendation: Set the distribution version from a module

Usually, distribution versions are set automatically from a primary module within the distribution. This is good -- we let the machine take care of it for us. It's one less thing for us to do, and helps to ensure machine-friendly distribution versions. That's good for binary packages like .rpm and .deb.

For example, using Module::Build, the 'module_name' parameter in Build.PL specifies the name of a module to examine for the distribution name and version.

use Module::Build;
Module::Build->new(
 module_name => 'Foo::Bar',
 license => 'perl',
)->create_build_script;

Or, using Module::Install, you can do the same thing with a Makefile.PL like this:

use inc::Module::Install;

name 'Foo-Bar';
all_from 'lib/Foo/Bar.pm';

WriteAll;

The underscore convention

It has been a long-standing CPAN convention that distribution version numbers containing an underscore are 'development' or 'alpha' versions, and the corresponding distribution files do not get indexed by PAUSE as a 'release' version.

DAGOLDEN/Test-Reporter-1.53_03.tar.gz

The three main build tools, ExtUtils::MakeMaker, Module::Build and
Module::Install will all attempt to parse a version number for a
distribution from a primary module file using the MM->parse_version() function provided by ExtUtils::MakeMaker. The parse_version() method looks for the first line in the file that appears to set $VERSION, and then calls eval() on that entire line.

The following sections show how to specify an alpha version in each of the three version number styles and some things to consider for each.

Decimal alpha version

our $VERSION = "0.001_001;
$VERSION = eval $VERSION;

For a decimal alpha version, the definition is split into two parts. The
first part provides the version in quotes, which is what gets returned by
MM->parse_version(). It has to be in quotes so that the underscore is preserved in the eval() call within parse_version(). Without quotes, parse_version() returns it as an ordinary decimal.

our $VERSION = 0.001_001; # WRONG: parse_version() gives 0.001001

The second line is required to make $VERSION an ordinary number at runtime. Without it, Perl would convert $VERSION to a number by truncating at the underscore, resulting in the wrong version number. ((Perl converts strings to numbers differently at runtime than how it parses numeric literals during compilation.))

Dotted-integer alpha version with v-strings

our $VERSION = v0.1_1;

For some versions of Perl, it's possible to specify an 'alpha v-string', with a final decimal point replaced with an underscore. ((This is an undocumented syntax feature/bug)) Consider a 'Foo module with a $VERSION line like the one above. Here's how different versions of Perl handle a request for a higher version number:

$ perl5.10.0 -e 'use Foo v0.1.2'
Foo version v0.1.2 required--this is only version v0.1_1 at -e line 1.
BEGIN failed--compilation aborted at -e line 1.

$ perl5.8.9 -e 'use Foo v0.1.2'

$ perl5.8.0 -e 'use Foo v0.1.2'
Foo v0.1.2 required--this is only v0.1.1 at -e line 1.
BEGIN failed--compilation aborted at -e line 1.

$ perl5.6.2 -e 'use Foo v0.1.2'

Note how Perl 5.8.9 and Perl 5.6.2 both succeed, even though a higher version is requested. One potential solution is to require the version.pm module. This 'fixes' 5.8.9, but fails in a different way for 5.6.2.

perl5.8.9 -Mversion -e 'use Foo v0.1.2'
Foo version v0.1.2 required--this is only version v0.1_1 at -e line 1.
BEGIN failed--compilation aborted at -e line 1.

perl5.6.2 -Mversion -e 'use Foo v0.1.2'
Foo version v0.1.2 required--this is only version v0.0.0 at -e line 1.
BEGIN failed--compilation aborted at -e line 1.

Dotted-integer alpha version with version objects

use version; our $VERSION = version->new("v0.1_1");

This form is visually similar to an alpha v-string, but by putting it in quotes and by passing it the version object constructor, the version is protected from idiosyncracies of different versions of the Perl interpreter.

On the surface, it seems like this is a good approach, but it still has problems if one tries to use() the same version on 5.8.0 and 5.6.2.

$ perl5.8.0 -e 'use Foo v0.1_1'
Foo version v0.1.1 required--this is only version v0.1_1 at -e line 1.
BEGIN failed--compilation aborted at -e line 1.

$ perl5.6.2 -e 'use Foo v0.1_1'
Foo version 0.011 required--this is only version v0.1_1 at -e line 1.
BEGIN failed--compilation aborted at -e line 1.

Requiring an alpha version as a decimal

The counter-examples in the previous sections assume a situation where an alpha version of a module is a prerequisite and show how an alpha v-string argument to use() means different things depending on the version of Perl and whether version.pm has been loaded.

The other alternative is to specify the version as a decimal.

use Foo 0.001_001;

While this is in the form of a decimal alpha version, the Perl parser sees this numeric literal as 0.001001. This works perfectly with the decimal alpha version example above that has the "$VERSION = eval $VERSION" line. Both are just numbers and they compare as equal.

That isn't the case for version objects. An alpha version object is not equal to a non-alpha version object, even if their numeric components are the same. If Foo has this version line:

use version; our $VERSION = version->new("v0.1_1");

then "use Foo 0.001_001" fails, even on a recent Perl.

$ perl5.10.0 -e 'use Foo 0.001_001'
Foo version 0.001001 required--this is only version v0.1_1

Recommendation: Don't use v-strings or version objects as alpha versions

There are just too many ways for alpha v-strings and version objects to be used incorrectly. Even if requiring Perl 5.10 or with version.pm, which a module author can control, if a user follows the three-digit convention and uses a decimal version in the call to use(), it can fail.

Other issues in the toolchain

There are several other ways in which version numbers refuse to be boring. Each could be an entire mini-essay, so I will only highlight a few of the issues I've found:

  • Module::Build can't handle v-string prerequisites unless they are quoted
  • ExtUtils::MakeMaker and Module::Install have trouble with v-string module versions and prerequisites, even if quoted or given as version objects
  • In at least one recent bug I've studied, an XS module failed to load with a version object created using the form "1.2.3" (without a leading-v)

Conclusion

I think version numbers should be boring. I don't want to have to think about how to write them and I don't want to make users think about how to format a version prerequisite. And I don't want to get bug reports about it when a user gets it wrong.

For me, a 'boring' version number must:

  • be expressed the same way in its definition, in use() checks, in prerequisites, in *.PL files and in META.yml
  • support the underscore convention in the same format
  • have similar behavior across different Perl versions
  • have similar behavior in use() when converted from X.YYYZZZ to vX.Y.Z format or vice-versa ((Remember that users might write a dotted-integer as a decimal, just like they are taught for Perl itself.))

Given these criteria, my recommendation is to use decimal version numbers, put them in quotes, and add a string eval:

our $VERSION = "0.001";
$VERSION = eval $VERSION;

This is safe and effective and always works. By putting any $VERSION in quotes, even if it isn't an alpha, you don't have to remember to add them if you ever change to an alpha version. (And numbers with trailing zeroes are nicely formatted when parsed for distribution versions.)

If you really want to have a dotted-integer module version, then I strongly recommend that you limit your module to Perl 5.10 (or require version.pm and at least Perl 5.8.1) and that you never use an alpha version number. Always quote your dotted integer version when you define it and always use a leading-v to guide your users towards proper usage.

It's unfortunate that version numbers are so complicated in Perl, but if you follow the recommendations in this article, your version numbers will be as boring as possible. And if you've read this all the way to the end, I hope I've convinced you that 'boring' version numbers are exactly what you want.

I would like to thank Curtis Poe, Ricardo Signes and Eric Wilhelm for reviewing a draft of this article and providing excellent suggestions for improving clarity and correctness. I would also like to thank the particpants in the #toolchain and #corehackers channels on IRC for being a sounding board as the article was developed. Thanks also go to John Peacock for his graceful acceptance of my criticisms and suggestions about version.pm.

This entry was posted in perl programming and tagged , . Bookmark the permalink. Both comments and trackbacks are currently closed.

31 Comments

  1. Andrew
    Posted August 5, 2009 at 8:55 pm | Permalink

    You've got an HTML escaping problem in your code blocks.

    • david
      Posted August 6, 2009 at 3:06 am | Permalink

      Thanks for the alert. I've fixed it once already and something in the "WYSIWYG" editor keeps reverting them. Will try again.

  2. Posted August 6, 2009 at 6:18 am | Permalink

    How about when you add version information to your "use" statements, like:

    package MyApp;
    use 5.008; ## I mean this to say minimum perl version 5.8

    Is the above okay and safe?

    • dagolden
      Posted August 6, 2009 at 6:28 am | Permalink

      Do you mean with long doubles? As far as I know, there is no problem. The issue is with how UNIVERSAL::VERSION converts $VERSION when given "use MODULE VERSION", but I don't believe that's invoked with the "use VERSION" syntax for checking Perl's own version.

  3. Richard Huxton
    Posted August 6, 2009 at 10:02 am | Permalink

    Thanks for an informative article. I'd have to say though that the main problem with Perl (module) versioning isn't the syntax or the charming quirks of its backward (in)compatibility. Here's a quote from perldoc for version.pm version 0.77:

    "All previous releases before 0.74 are deprecated and should not be used due to incompatible API changes."

    That means it doesn't matter what syntax is used to express the version-number, the only meaning I can attach to it is that if V2>V1 then it was released at a later date.

    For me, the whole point of a version number is to advertise API changes. The fact that version.pm can't get that right doesn't send out good signals.

    • dagolden
      Posted August 6, 2009 at 11:06 am | Permalink

      I've found that a common convention is usually to bump the major version number when an API changes, but that is only a convention, as version.pm shows. (version.pm is an unusual module in that it duplicates code in the Perl 5.10 core to provide it to older Perl's, so there are limits to the API it can provide.)

      The broader problem with API compatibility in Perl is that "use Foo 1.23" means "any version of Foo >= 1.23". What you'd like to be able to say is something like "use Foo 1.*" and get any version of Foo that offers the version 1 API.

      • Richard Huxton
        Posted August 6, 2009 at 12:36 pm | Permalink

        The broader problem with API compatibility in Perl is that “use Foo 1.23″ means “any version of Foo >= 1.23″. What you’d like to be able to say is something like “use Foo 1.*” and get any version of Foo that offers the version 1 API.

        If the version numbers had meaning, someone would fix that within 5 minutes. We're not short of clever hackers in the community.

        There are times when We Don't Need So Many Ways To Do It. A top-level pronouncement on how version-numbering should be done for any module to get a gold rating would be useful.

        • cbt
          Posted August 6, 2009 at 12:45 pm | Permalink

          Top level? Who exactly would that be? The inmates have been running the asylum for a long time now.

          • Richard Huxton
            Posted August 7, 2009 at 10:15 am | Permalink

            Yeah, but if Joker, Riddler and Two-Face say there's a break-out tonight, then that's when it is.

            Start with the most volatile modules in http://ali.as/top100/ and work down the list. By the time you reach 50 momentum would probably buy you the rest.

    • Posted August 6, 2009 at 4:17 pm | Permalink

      There's no way to force what an author means when the increment their version number, and I don't think a pronouncement is going to carry much weight. Its wishful thinking that you can know what changed between 1.2.3 and 2.3.4. Maybe 1.y.z to 2.y.z means an API change, maybe it doesn't. What does x.2 to x.3 indicate? Is 1.2.3 stable and 1.3.1 development? Who knows? Gotta find these things out per project.

      What this really is is metadata. Rather than trying to encode it in numbers and perform version numerology it should just live as meta data in META.yml and in something accessible by querying the installed module.

      • Richard Huxton
        Posted August 7, 2009 at 10:19 am | Permalink

        Is 1.2.3 stable and 1.3.1 development? Who knows? Gotta find these things out per project.

        That's back to the old debate about what cpan is - a place for producers to upload stuff or a place for consumers to find useful stuff.

        I think a pronouncement would be useful - "if you want to turn up in the main section of cpan your module will meet the following conditions... (use strict, version numbering, tests etc)". Again, that depends on what you think cpan should be of course.

  4. John
    Posted August 9, 2009 at 10:19 am | Permalink

    David, could you please give an example of how version number progression would look over time using your proposal? As in:

    0.001 -- initial release
    0.002 -- some minor bug-fixes
    0.003 -- major overhaul in $foo subsystem. API changed.
    0.004 -- updated docs with minor spelling errors
    0.005 -- another break in compatibility with prev versions
    0.006 -- added a missing comma in the README.txt

    • dagolden
      Posted August 9, 2009 at 1:54 pm | Permalink

      I would tend to bump the integer part for any incompatible changes. So if you imagine a version X.00Y00Z, I would bump X for incompatible API changes, bump Y for major fixes or new features and bump Z for minor fixes, doc changes or incremental work on an alpha.

      So, in your example:

      0.001 — initial release
      0.001001 — some minor bug-fixes
      1.000 — major overhaul in $foo subsystem. API changed.
      1.000001 — updated docs with minor spelling errors
      2.000 — another break in compatibility with prev versions
      2.000001 — added a missing comma in the README.txt

      Despite my advice and examples in the article starting with "0.001", I tend to still use two-decimal versions so there aren't so many 0's padding up the version numbers in the example above.

      • Bill Costa
        Posted July 2, 2012 at 12:59 pm | Permalink

        I agree that the version number should be meaningful to the computer, but as a human I want to easily get meaning from it as well. The idea of Semantic Versioning is not new, but this page does a nice job of rigorously defining what a version means.

        • Xiong Changnian
          Posted February 8, 2013 at 3:46 pm | Permalink

          Thank you, Mr. Costa.

          Engineering is about standards. Semantic Versioning is the standard. The author, Tom Preston-Werner, did not create the standard; he merely codified it.

          All objections to adhering to this clear standard boil down to "I don't want to be an engineer." Fine; be an artist. Be free.

          • Posted February 8, 2013 at 4:27 pm | Permalink

            Keep in mind that semver.org was created in December 2009.

            Perl's use module VERSION syntax (checking $VERSION as a number) was introduced in Perl v5.4, released in May 1997.

            Perl's v-strings were introduced in Perl v5.6, released in March 2000.

            Version objects were introduced in Perl v5.10, released in December 2007.

            The peculiarities of version number representation in Perl existing well before anyone bothered to write and publicize a particular standard.

  5. John
    Posted August 9, 2009 at 8:17 pm | Permalink

    I'm not sure I understand: why not just always use 3-digit dotted-integer version strings -- and *always* write them with quotes around them? That is, just always put quotes around things like "1.2.3" and patch `use Module VERSION` to work with that? Require them to always take the form of `m{\d+\.\d+\.\d+}`? Was this not considered back when "accident #2" happened way-back-when?

    The "major-version.minor-revision.bugfix" scheme seems to be pretty well accepted across the industry, and makes a lot of sense to me.

    • dagolden
      Posted August 9, 2009 at 8:38 pm | Permalink

      I believe that what you describe, "v1.2.3", works fine for Perl 5.10. The "problem" is that many CPAN authors write their code so that it can be used on older versions of Perl as well. The article shows many examples of how dotted-integers are interpreted differently on older Perl interpreters.

  6. Sawyer
    Posted August 11, 2009 at 2:04 am | Permalink

    I didn't get from the article the purpose of the eval().

    What is it for?

    • dagolden
      Posted August 11, 2009 at 6:29 am | Permalink

      The eval converts the string "0.001_001" to a number, following the rules for Perl numeric literals (which allow underscores for visual separation). The result is the number 0.001001.

      Without the eval, the string is converted to a number following the rule for converting strings, which stops at the first non-numeric character.

      E.g.: perl -e 'print "0.001_001" + 0'

      • Sawyer
        Posted August 13, 2009 at 2:12 am | Permalink

        Alright, so that's for those type of string. I get that.

        If you use '0.46' or that sort of schematic, do you still require the eval(), or would you keep it just for good practice?

        • dagolden
          Posted August 13, 2009 at 3:10 am | Permalink

          In my own code, I include the eval() line even if I don't technically need it (e.g. for '0.46) so that if I ever decided I needed '0.46_01', I don't need to remember to add eval(). My recommendation is intended to be something that you can add once to your code, then stop thinking about ever again except to bump up the number.

  7. Ben Morrow
    Posted August 11, 2009 at 6:43 am | Permalink

    You missed the all-important rule for XS authors that the version passed to XSLoader::load or DynaLoader->bootstrap must match exactly the version string MakeMaker compiled into the module. Hence the common idiom
    our $XS_VERSION = our $VERSION = "0.01_02";
    $VERSION = eval $VERSION;
    XSLoader::load __PACKAGE__, $XS_VERSION;

  8. Abigail
    Posted August 12, 2009 at 1:47 am | Permalink

    My biggest peeve with version numbers is that their ordening is non-intuitive to me. I've always seen version numbers as integers separated by dots - and that's how many tools and other people see them as well. For me, '9' is followed by '10'. But in Perls toolchain, version "x.10" is considered to be older than version "x.9". That, and all the stuff mentioned in your article had me recently decide to switch to DNS style version numbers: YYYYMMDDXX, where YYYYMMDD is the date I make the release, and XX a sequence number to be reset to "01" each day (for those cases I spot a typo immediately after putting in on PAUSE).

    This loses the convention of signalling the impact of the change by updating a part of the version number that isn't after the last dot, but that was a convention that everyone uses differently anyway. With YYYYMMDDXX numbers, there are no dots, no unexpected translations (AFAIK), and every tool and human orders them the same.

    • Posted August 13, 2009 at 7:18 am | Permalink

      This++

      I'm sorely tempted to make the problem go away and just have my release process just set $VERSION=N.YYYYMMDDHHMMSS where I may or may not remember to update N for major changes. Indeed, two of my modules (Number::Phone::UK::{Data|Exchanges}) already do that.

      That has the advantage over your method of not requiring a manual sequence number, and also not overflowing a 32 bit signed int.

  9. demerphq
    Posted August 13, 2009 at 5:20 am | Permalink

    Ben: I dont think that is completely true. I have worked a number of times on projects where VERSION!=XS_VERSION. I dont recall the details, but it is possible to setup makemaker so that you can have two numbers be different.

  10. Posted October 28, 2009 at 12:07 am | Permalink

    For the last few years, the practice I have followed for the modules I write is to use X.Y.Z version numbers conceptually and in my documentation and as my distro version, and I use the corresponding X.00Y00Z versions in the actual code of my modules for declaration and use. I increment X for a total rewrite (generally I've never incremented X yet), I increment Y for each update that is either of substantial content (which might just be to documentation) or that introduces an API change, either backwards-compatible or not (so far at least 80% of updates are this kind), and I increment Z for just bug fixes or minor updates that don't change the API. My very first release of any module that isn't production ready from the start has version 0.0.0 because it is the first release of a major series, that is a X.0.0, and X is 0; I then typically go to 0.1.0 or 0.0.1 etc for the next release.

  11. Joey
    Posted April 20, 2010 at 11:30 pm | Permalink

    With all due respect, I'm not going to pollute my code with '$VERSION = eval $VERSION', no matter what other nonsense that leaves it open to. Because I would have to accompany that with a comment that said "go read this enormous article, and then you may understand why this eval is here", and I just can't inflict that on someone who has to maintain my code.

    So, at the moment, you've convinced me that I should avoid versioning my perl modules. Looking forward to something better..

    • mike
      Posted July 15, 2013 at 11:42 pm | Permalink

      you could just put the simple comment which explains enough to cover why the eval is used

      # eval converts string to number following rules for numeric literals which allow underscores for visual separation

  12. samlin
    Posted March 31, 2011 at 7:16 pm | Permalink

    I see many XS modules failing on 5.6.2 when they use your recommended approach. Because the eval results in stringified version of the number in scientific notation, which does not match the decimal format:

    $ perl5.6.2 -e 'our $VERSION="0.01"; print eval $VERSION'
    1.e-02

    • Posted March 31, 2011 at 8:15 pm | Permalink

      That's an interesting discovery. Much of this article doesn't apply to XS modules, as the version comparison between XS and the .pm file happen through different mechanisms than normal version comparison.

3 Trackbacks

© 2009-2014 David Golden All Rights Reserved