I've seen that Perl allows you to put a use VERSION statement at the top of the file, e.g.
use v5.16.3;
which results in a compiler error if the current version of the interpreter is smaller.
Is it good practice to specify the version number?
According to comments, you should use VERSION; only if your scripts depend on some language features or bug fixes which cannot be found in minor versions. For example using say, which is added in Perl 5.10.
Also, you can use Syntax::Construct to state which non-feature constructs you want to use in your code.
Related
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;
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.
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
perlmodstyle
version
"strict" version rules
"Version numbers should be boring"
Perl::Critic::Policy::ValuesAndExpressions::ProhibitVersionStrings
Perl::Critic::Policy::ValuesAndExpressions::RequireNumericVersion
It is incompatible with semver.
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.
I'm a Moose newbie and I wonder if the common
our $VERSION = "0.001";
$VERSION = eval $VERSION;
should also be used in Moose packages, or Moose has some alternative way for version control. Couldn't find a reference in Moose docs.
As with all perl packages, it is usually a good idea to have a $VERSION defined in them. This allows other things to properly depend on the version of them with all the features they need, either by declaring a dependency in their Makefile.PL or equivalent, or directly when loading the module using use SomeModule 1.23;.
The eval construct you're showing is a kludge. There is a distinction between regular releases of a module, and development releases. Traditionally that has been indicated by a $VERSION with an underscore in it. That means something like 0.001 would be a normal, stable release, while something like 0.001_01 would be a development release.
The eval is used to get rid of that underscore at runtime, while still preserving it in the version string that the various tools, including PAUSE, the Perl Authors Upload SErver, extract. This is to avoid warnings such as 0.001_01 is not numeric in ....
You'll find that idiom in lots of code. Luckily, there's a good alternative to it. Instead of indicating the development vs. non-development status in the version number of individual modules, you can also do that in the release tarball that you might upload to CPAN by using the -TRIAL flag.
Instead of uploading your distribution as My-Distribution-0.001.tar.gz, you can rename it to My-Distribution-0.001-TRIAL.tar.gz. The CPAN tools will pick that up and treat it as a development release accordingly. Note that -TRIAL is not part of the $VERSION, only of the tarball name. Therefore the eval kludge becomes unnecessary.
Also note that there are alternative ways to declare a package's $VERSION. As of perl 5.12.0, you are able to declare it right with in the package declaration:
package My::Package 0.001;
However, none of this is specific to Moose in any way.
I thought I knew how to declare version numbers for modules. But after reading the article "$VERSION Confusion" at Modern Perl Books, a Modern Perl Blog; I'm now more confused than I started. (Ignorance was indeed bliss.) Not that I have hangups about "perfect" code but I'm just really curious why such a trivial matter apparently has no definitive answer for such a mature language.
Hope the SO community can find a definitive answer to this question as there are better things for Perl hackers to do than argue about different ways to declare version numbers.
use Module VERSION
If the VERSION argument is present between Module and LIST, then the use will call the VERSION method in class Module with the given version as an argument. The default VERSION method, inherited from the UNIVERSAL class, croaks if the given version is larger than the value of the variable $Module::VERSION.
That makes for a straightforward pattern:
package MyModule;
our $VERSION = 1.23;
# ...
1;
My position is keep it simple. Declare your version as a string containing a floating point number. Leave the multiple-decimal stuff for Perl's version numbers and Perl 6.
If your module requires Perl 5.6.0 or later:
our $VERSION = '1.02';
Or, if you need to remain compatible with Perl 5.005 or older:
use vars '$VERSION';
$VERSION = '1.02';
Some additional points:
Always use the same number of digits after the decimal point. Some (non-Perl) packaging tools think version 1.11 comes after 1.9 but before 1.90. If you need to change the number of digits you use, increment the major version number at the same time.
Always declare the version as a string. This keeps trailing zeros from disappearing. (See point 1.)
If you want to make an unstable (e.g. alpha or beta) release, append the string -TRIAL to the distribution's version number (e.g. upload Foo-Bar-1.90-TRIAL.tar.gz containing Foo::Bar 1.90). This tells CPAN to list it as a development release, just as if it contained an underscore. Dist::Zilla makes it easy to make trial releases.
A string containing a floating point number will work with all versions of Perl, all versions of MakeMaker & Module::Build, and all Linux distributions I'm aware of.
Most of your confusion is, I suspect, due to the page you linked advocating 1.2.3 style version "numbers". These are not fully supported throughout all the toolchain (regardless of what others may say) and should not be used. They offer no advantage over a simple numeric version, since they must for compatibility be treated as just a number in many places (e.g. 1.2.3 is treated as 1.002003).
The correct way to declare a version number is simple, unless you have an XS component or a alpha/beta indicator (_ in the version number), since then some things need to see a version string and some things a version number. Then it gets more complicated. perlmodstyle provides the correct incantation:
If you want to release a 'beta' or
'alpha' version of a module but don't
want CPAN.pm to list it as most recent
use an '_' after the regular version
number followed by at least 2 digits,
eg. 1.20_01. If you do this, the
following idiom is recommended:
$VERSION = "1.12_01";
$XS_VERSION = $VERSION; # only needed if you have XS code
$VERSION = eval $VERSION;
(This assumes $VERSION and $XS_VERSION have already been declared; if not, simply add our to the first two lines.)
The standard for perl version is described in the module version and there are two types:
dotted decimal style like the one used by perl itself, i.e. v5.8.32
or just 5.8.32; or
decimal style such as 1.0203
In dotted-decimal style, which is the recommended style, the three digits represent respectively major, minor and patch. More on this here on the Wikipedia page
Alpha versions are marked with digits separated from the rest by an underscore, such as: 5.8.32_01
The requirements advocated by perl are:
"Always use a dotted-decimal with (at least) three components"
"Always use a leading-v"
"Always quote the version"
Thus, when declaring a version in a perl module, one would simply use something like:
package MyModule;
BEGIN
{
use strict;
use warnings;
our $VERSION = 'v1.2.3';
};
# some code here
1;
__END__
When using a module, as per the perl documentation, one would write:
use Module 12.34;
which is equivalent to:
BEGIN { require Module; Module->VERSION(12.34) }
I'm a bit confused by conflicting advice between pre-5.10.0 documents and the more recent version module. Perl Best Practices makes it pretty clear that version strings ('v1.0.3') are bad and one is supposed to specify a version as follows:
use version; our $VERSION = qv('1.0.3');
but the version module says that we're back to using version strings:
use version 0.77; our $VERSION = qv("v1.2.3");
Have we regressed, or is there a reason behind this?
Your quote from Perl Best Practices is not quite right. Specifically, bare vstrings of the form
our $VERSION = v1.0.3;
are discouraged. In the latest version of version.pm, the recommendation is to use true strings:
use version 0.77; our $VERSION = qv("v1.2.3"); # shorthand
This functionality has been added to aid readability, while specifically avoid the traps of bare strings described here.
As the doc page you linked to says, you can use versions without the pre-pending 'v' using built-in logic in Perl 5.10:
If you have a module that uses a decimal $VERSION (floating point), and you do not intend to ever change that, this module is not for you. There is nothing that version.pm gains you over a simple $VERSION assignment.
So the answer to your question is: use the new "v1.0.3" syntax if you are writing new code that uses version.pm. Stick to a plain number if that is how your old code was written, or if you don't want to depend explicitly on module.pm.
When it come to saying what version of Perl we need for our scripts, we've got options, oh, brother, we've got options:
use 5.010;
use 5.010_001;
use 5.10.0;
use v5.10;
use v5.10.0;
All seem to work. perlcritic complains about all but the first two. (It's unfortunate that the v strings seem to have such flaws, since Perl 6 expects you to do use v6; for your Perl 6 scripts...)
So, what should we be doing to indicate that we want to use a particular version of perl?
There are really only two options: decimal numbers and v-strings. Which form to use depends in part on which versions of Perl you want to "support" with a meaningful error message instead of a syntax error. (The v-string syntax was added in Perl 5.6.) The accepted best practice -- which is what perlcritic enforces -- is to use decimal notation. You should specify the minimum version of Perl that's required for your script to behave properly. Normally that means declaring a dependency on language features added in a major release, such as using the say function added in 5.10. You should include the patch level if it's important for your script to behave properly. For example, some of my code specifies use 5.008001 because it depends on the fix for a bug that 5.8.0 had which was fixed in 5.8.1.
I just use something like 5.010_001. I've grow weary of dealing with version string problems for something that should be mind-numbingly simple.
Since I mostly deal with build systems, I have the constant struggle of Module::Build's internal version.pm which is out of sync with the version.pm on CPAN. I think that's mostly better now, but I have better things to think about.
The best practice should always be to do the thing that commands the least of your attention, and certainly not take more attention than the value it gives back. In my opinion, v-strings and dotted decimals were a huge distraction with no additional benefit, wasting a lot of valuable programmer time just to get back to the starting point.
I should also note that Perl::Critic has often pushed questionable practices for the higher purpose of reducing the ways that people do things. However, those practices often cause problems, make them un-best. This is one of those cases. A more realistic best practice is to not make Perl::Critic compliance your goal. Use it where it is useful, but in cases like this, don't waste mental time on it.
The "modern" way is to use the forms starting with v. However, that may not necessarily be what you really want to do.
Critic complains because older versions of Perl won't understand and play nicely with the forms that start with v. However, if your version of Perl supports it, v is nicer to read because you can say:
use v5.10.1;
... rather than ...
use 5.010_001;
So, in the documentation for use, the following workaround is offered:
use 5.006; use v5.6.1;
NB: I think the documenation is in error here, as the v is omitted from the example at perldoc use.
Since the versions of Perl that don't support the v syntax will fail at the first use, they won't get to the second more specific and readable one.