15

Modules are cool especially when they come with versioning. You can define minimum module version to prevent leak of methods you want to use. But with every light side there comes a dark side which means Perl's TIMTOWTDI.

After nearly seven years as a Perl developer I saw and wrote version declarations in many ways. Some are easily to point as bad, some not. As no one can know a language completely I would like to ask you guys whats the pros and cons of the following software versioning in Perl is.

Please don't hesitate to comment more ways of version definition if you find one leaking ;)

Please respect:

  • weird require/use of module that may cause trouble detecting module's version (compile vs runtime)
  • PAUSE/CPAN parsing (and other common services)
  • readability for end users
  • maintainability for developers

What are the pros and cons about declaring package version methods in Perl?

Method 1

package PackageName;
BEGIN {
  use version 0.77; our $VERSION = version->new('v0.0_1');
}

Method 2

package PackageName;
BEGIN {
  our $VERSION = 0.000_01;
}

Method 3

package PackageName;
BEGIN {
  our $VERSION = 0.0.1;
}

Method 4

package PackageName;
use version 0.77; our $VERSION = version->new('v0.0_1');

Method 5

package PackageName;
our $VERSION = 0.000_01;

Method 6

package PackageName;
our $VERSION = 0.0.1;
burnersk
  • 3,320
  • 4
  • 33
  • 56

3 Answers3

8

The correct answer is, do this:

package My::Thing;
our $VERSION = "0.001";

The version should always be a decimal number, using the three-digit split convention. The above version would be shortened to v0.1.0, to change the 3rd step in that abbreviated form you would define your version like this: 0.001001, which would be v0.1.1 abbreviated.

Do not put underscores into your version number to mark dev releases. The Perl toolchain has since adopted the -TRIAL mechanism, as exemplified by Dist::Zilla 4.101800-TRIAL. The advantage of that is that the version numbers in your code need no changes. Only the release filename and meta files are modified from the norm by adding -TRIAL.

Edit:

After reading daxim's answer and pondering a bit, i have to agree on putting the version number in quotes. It does not change the functionality in any way, but reduces the chances of 0.00101 being mistaken for v0.1.1, when it is in fact v0.1.10 and is more clearly read as 0.001010.

Mithaldu
  • 2,393
  • 19
  • 39
  • "you would define your version like this: 0.001001, which would be v0.1.1" Those two are not the same, and the latter has issues. (It requires special handling, which means it can't be printed for starters.) If you want `v0.1.1` (and I do), use version, which brings us back to my answer. – ikegami Jul 12 '13 at 14:29
  • `perl -e 'print 1 if version->parse(0.001001) == version->parse(v0.1.1)'` ⟶ `1` – Mithaldu Jul 12 '13 at 15:00
  • Also note i never said to use v-strings, i said to use simple decimal numbers. – Mithaldu Jul 12 '13 at 15:02
  • you said "which would be v0.1.1 abbreviated.", It's not. `version->parse(v0.1.1)` is also not the same thing as `v0.1.1`, so that's pointless. `perl -le'print 1 if 0.001001 == v0.1.1'` is the pertinent test, or even just `perl -le'print v0.1.1'`. The fact that had to use version makes my point. – ikegami Jul 12 '13 at 15:31
  • I don't see your point to be honest. It seems to me you're arguing semantics, not practicality. – Mithaldu Jul 12 '13 at 21:27
  • Version numbers should be boring, so I advise against the usage of "-TRIAL" and suggest to use the well understood underscore notation for dev releases. Or can anybody tell me why `version->new("4.101800-TRIAL")` does not work? – Slaven Rezic Jul 12 '13 at 22:02
  • Slaven, it's not supposed to. The trial marks for the pause/sco/metacpan/CPAN.pm toolchain that that distribution is a trial distribution, not to be indexed as authorative nor installed by default, nothing else. The version numbers of the modules inside do not change from the simple numbers they are and are not required to include underscores, text, or even -TRIAL to gain the behavior described above. Dist-Zilla-4.101800-TRIAL.tar.gz contains Dist::Zilla 4.101800 and will act as such when installed, but will not be indexed by PAUSE nor installed by default by CPAN.pm. I hope this explains it. – Mithaldu Jul 13 '13 at 11:52
  • Even worse. So it's possible that there are two Dist/Zilla.pm files around in the world which are not identical, but share the same version number? – Slaven Rezic Jul 14 '13 at 21:28
  • Yes. That's not a big problem though, since whoever installs the TRIAL one had to consciously jump through hoops to do it. – Mithaldu Jul 15 '13 at 10:03
  • Certainly it's a problem for dependency analysis of fail reports in CPAN testers. In the test reports only the module version is visible in the dependency section, but not the distribution version. – Slaven Rezic Jul 15 '13 at 17:48
  • You're right, that would be bad. I did forget to mention something though. Normally if you did cut a TRIAL and it went successfully, you'll increment the version number afterwards, similar to how perl has dev and stable releases with different versions. Note that there is no https://metacpan.org/release/RJBS/Dist-Zilla-4.101800 – Mithaldu Jul 15 '13 at 18:31
  • 1
    There's also a fun benefit of quoting: our $VERSION = 0.001000 # runs the risk of being truncated and the extra precision being lost, unless you're using pure static analysis. Quoting prevents this precision loss. – Kent Fredric Jan 04 '14 at 11:19
6

Best practices according to me after lurking years in #toolchain and various module-related mailing lists.

examples

For modules:

package Foo::Bar 2.001; # 2nd version of revision 2
package Fnord 2.420;    # 421st version of revision 2

Otherwise:

our $VERSION = '2.001'; # 2nd version of revision 2
our $VERSION = '2.420'; # 421st version of revision 2

rationale

Every module must have a version or else it is problematic to accurately specify a dependency when a distribution is split. It works best when the distribution version and each module's version are equal and increased in lock-step. To to make this easy, use perl-reversion, which is part of Perl::Version. Increase a version each time when you need to depend on a new features or a changed API from code external to the distribution.

When using the package declaration, a version is a rational number. If a package declaration is not suitable, declare the magic $VERSION variable and then a version is a string.

In any case, the version consists of a revision number, a literal dot as separator and a version number, altogether in the form y.xxx. y is a natural number, xxx are exactly three zero-padded digits. String quoting prevents trailing zeroes from disappearing. Padding to the same amount of digits prevents confusion about 1.10 < 1.9. Having exactly one separator prevents confusion about 5.10.1 == 5.010001.

Do not use the version module for declaring versions. Using plain strings prevents that ugly v prefix in a distribution tarball name. However, using the module to handle versions, e.g. for comparing them, is a good idea.

Do not use v-strings. They are poorly understood.

Do not use underscores. Using underscores require to eval the version to turn it into a number. If you want to mark a distribution as release candidate to the PAUSE indexer, add the word TRIAL to the distribution name.

A version should be accessed through the universal VERSION class method only.

perl -mLWP::Simple -E'say LWP::Simple->VERSION'

compliance

This scheme is fully compatible with the advice laid out in

It is incompatible with semver.

daxim
  • 39,270
  • 4
  • 65
  • 132
2

4. Good. Using version will have fewer corner cases.
5. Ok.
6. (Short for v0.0.1) Let's avoid v-strings, please?

The BEGIN does make a difference (populate $VERSION before the following lines are compiled), but that difference is useless.

ikegami
  • 367,544
  • 15
  • 269
  • 518
  • 1
    I think you mixed something up here. Case 1 and case 4 are identical aside from the begin, but you called 1 good and 4 bad. – Mithaldu Jul 12 '13 at 13:37
  • Also, 5 is not ok, 5 will parse to 0.0.10. – Mithaldu Jul 12 '13 at 13:39
  • I could have sworn that (4) didn't have `use version 0.77;` when I starting composing my answer. Adjusting my answer for the question as it now stands. – ikegami Jul 12 '13 at 13:40
  • (4) actually works without `use version 0.77;`, but like I said, that's undocumented and unsupported. – ikegami Jul 12 '13 at 13:41
  • @ikegami: would you extend your answer to explain the corner cases when using `version`? – burnersk Jul 12 '13 at 13:59
  • No. That's the whole point. version can handle problems, so that I don't have to know what they are. It also gets you improvements from newer versions of Perl without using newer versions of Perl. – ikegami Jul 12 '13 at 14:23
  • I misunderstand your point. I thought `version` would break something rarely. Now I get it ;) – burnersk Jul 12 '13 at 14:25