Version::Dotted - Bump a dotted version, check if version is trial


Version v0.0.1, released on 2017-01-04 21:35 UTC.


Version::Dotted and its subclasses are authoring time extensions to core version class: they complement version with bump operation and implement alternative trial version criteria.

This is Version::Dotted module documentation. Read it first because it contains many relevant details, and use one of subclasses.

General topics like getting source, building, installing, bug reporting and some others are covered in the README.


    use Version::Dotted;        # import nothing
    use Version::Dotted 'qv';   # import qv

    # Construct:
    $v = Version::Dotted->new( v1.2.3 );    # same as qv( v1.2.3 )
    $v = qv( v1.2.3 );      # v1.2.3
    $v = qv( 'v1.2.0' );    # v1.2 (trailing zero parts ignored)
    $v = qv( 'v1' );        # v1

    # Access parts:
    @int = $v->parts;       # Get all parts.
    $int = $v->part( $i );  # Get i-th part (zero-based).

    # Bump the version:
    $v->bump( $i );         # Bump i-th part
                            # and drop all parts behind i-th.

    # Determine release status:
    $bool = $v->is_trial;

    # Stringify:
    $str = $v->stringify;   # "v1.2.3"
    $str = "$v";            # ditto

    # Compare:
    $bool = $v >= v1.2.3;
    $bool = $v <=> 'v1.2.3';



Version::Dotted is authoring time extension to version. It means Version::Dotted and its subclasses are intended to be used in authoring tools (like Dist::Zilla plugins) when author prepares a distribution. Version::Dotted and its subclasses serve for two purposes:

  1. To bump a dotted version.

  2. To implement alternative trial version criteria not depending on underscore character.

Version::Dotted is not required to build, install, and use module(s) from prebuilt distribution, core version works at these stages.

See also "WHY?".

Types of Versions

Historically, two types of version numbers are used in Perl: decimal and dotted.

Version::Dotted handles only dotted versions, no support for decimal versions is provided intentionally.


"Bumping" means incrementing a version part by one and dropping all the parts behind the incremented. For example, bumping the third part of v1.2.3 gives v1.2.4, bumping the second part of v1.2.4 gives v1.3 (the third part is dropped).

Trial Versions

Firstly, Version::Dotted prefers "trial" term to "alpha" (see "Non-Stable Releases").

Secondly, trial versions are not denoted by underscore character anymore (see "WHY?"). Version::Dotted defines interface, exact criteria are implemented in subclasses.


Version::Dotted is heavily influenced by Perl::Version, but Version::Dotted is not a subclass of Perl::Version.

Version::Dotted it is a subclass of version. Version::Dotted extends versionVersion::Dotted objects are modifiable, but it also narrows versionVersion::Dotted creates only dotted (aka dotted-decimal) version objects.

Error Reporting

The class reports error by warnings::warnif. It gives flexibility to the caller: warning may be either suppressed

    no warnings 'Version::Dotted';

or made fatal:

    use warnings FATAL => 'Version::Dotted';


The module exports nothing by default.

The module installs qv function (not a method) into caller namespace by explicit request:

    use Version::Dotted 'qv';

If caller module already has qv function, warning is issued and function is redefined.

Note: version exports qv by default, if caller package does not have qv function yet.

The module (unlike to version) does not play any tricks with importer's VERSION and/or UNIVERSAL::VERSION.



Minimal number of parts, read-only.

    $int = Version::Dotted->min_len;    # == 1

Objects are maintained to have at least minimal number of parts. In Version::Dotted minimal number of parts is 1, subclasses may raise the bar.



Constructs a new version object.

    $obj = Version::Dotted->new( $arg );

The constructor accepts one argument and creates dotted version object. An argument can be either integer number (1), floating point number (1.2), v-string (v1.2), or string (with or without leading v: '1.2', 'v1.2'), or version object. Trailing zero parts may be stripped (if number of parts exceeds required minimum), leading zeros in parts are insignificant:

    Version::Dotted->new( 1.2.0 ) == Version::Dotted->new( v1.2 );
    Version::Dotted->new( 1.002 ) == Version::Dotted->new( v1.2 );

However, to avoid surprises (see "Leading Zeros" and "Trailing Zeros") it is better to stick to using v-strings or strings, using numbers is not recommended (and may be prohibited in future).


Prints warning "Method 'parse' is not supported" and returns undef.



Returns all parts of the version.

    @int = $v->parts;   # Get all parts.

In scalar context it gives number of parts in the version object:

    $int = $v->parts;   # Get number of parts.


Returns i-th part of the version.

    $int = $v->part( $i );  # Get i-th part.

If index is larger than actual number of version parts minus one, undef is returned.

Negative part index causes warning but works like index to regular Perl array: -1 is index of the last version part, -2 — second last, etc.


Bumps i-th version part.

    $v->bump( $i );

"Bumping" means incrementing i-th version part by one and dropping all the parts behind i-th:

    $v = qv( v1.2.3 );  # $v == v1.2.3
    $v->bump( 3 );      # $v == v1.2.3.1
    $v->bump( 2 );      # $v == v1.2.4
    $v->bump( 1 );      # $v == v1.3
    $v->bump( 0 );      # $v == v2

If index is larger than actual number of version parts, missed parts are autovivified:

    $v->bump( 5 );      # $v == v2.

Negative part index causes warning but works.

The method returns reference to version object:

    $v->bump( 2 )->stringify;


Returns true in case of trial version, and false otherwise.

    $bool = $v->is_trial;

This method always returns false, but descendants will likely redefine the method.

See also "Non-Stable Releases".


The method does the same as is_trial but prints a warning.


Returns version string with leading 'v' character.

    $str = $v->stringify;

See also "Stringification".


The same as stringify.

    $str = $v->normal;

See also "Stringification".


Prints warning "Method 'numify' is not supported" and returns undef.

See also "Stringification".



Shortcut for Version::Dotted->new.

    $v = qv( $arg );    # same as $v = Version::Dotted->new( $arg );

(If the function is imported from Version::Dotted subclass, it would be shortcut for Version::Dotted::Subclass->new.)

The function is prototyped. It takes one scalar argument:

    ( $v, $w ) = qv v1.2.3, v1.2.3;

$v will be a Dotted::Version object, $w will be a v-string. (version's qv grabs entire list but uses only the first argument, $w will be undefined.)

Note: There is no function qv in Version::Dotted package, the function is installed into importer package by explicit request, see "EXPORT".



Compares two versions.

    $v <=> $other;

The operator is inherited from parent's class (see "How to compare version objects" in version). However, there is a subtle difference: if $other is not a version object, it converted to a version object using new (not parent's parse).

Other comparison operators (e. g. <, >, <=, etc) are created by Perl.


The same as <=>.


Returns version string.

    $str = "$v";

The same as stringify.


Leading Zeros

Leading zeros in parts are insignificant:

    qv( v01.02.03 ) == v1.2.3;
    qv( 1.002 )     == v1.2;

However, Perl interprets numbers with leading zero as octal, so be aware of:

    qv( 010     ) == v8;    # 010 == 8
    qv( 010.011 ) == v89;   # 010.011 eq 8 . 9 eq "89"

To avoid surprises stick to using v-strings or strings:

    qv(  v010      ) == v10;
    qv(  v010.011  ) == v10.10;
    qv( 'v010.011' ) == v10.10;

Trailing Zeros

Perl ignores trailing zeros in floating point numbers:

    1.200 == 1.2;


    qv( 1.200 ) == v1.2;    # not v1.200

To avoid such surprises stick to using v-strings or strings:

    qv( v1.200  ) == v1.200;
    qv( '1.200' ) == v1.200;



The parent class version works with dotted and decimal versions and has three stringification methods:

    $v->stringify;  # as close to the original representatiion as possible
    $v->numify;     # (convert to) decimal version
    $v->normal;     # (convert to) dotted version with leading 'v'

normal and numify are used to convert a version to specified form, dotted or decimal respectively, regardless of its actual type:

    version->parse( 1.003010 )->normal;     # eq "v1.3.10"
    version->declare( v1.3.10 )->numify;    # eq "1.003010"

Version::Dotted works with dotted versions only. normal returns dotted version string with leading 'v' character (like parent does), stringify does exactly the same, numify is not supported:

    $v->normal;     # dotted version with leading 'v'
    $v->stringify;  # same as normal
    $v->numify;     # prints warning & returns undef

Practically it means Version::Dotted has only one stringification method. Since there is no place for conversion, stringify is the preferred name for it.

Using version

version is an Perl core module. It serves for two purposes:

  1. Declare package version. version module can be used either explicitly (works for any Perl version):

        package Assa;
        use version 0.77; our $VERSION = version->declare( 'v1.2.3' );

    or implicitly (works for Perl 5.12.0 or later):

        package Assa v1.2.3;

    In the second case Perl automatically assigns $VERSION variable an object of version class.

  2. Compare package versions:

        version->parse( $Assa::VERSION ) >= 'v1.2.3';

Decimal Versions

Decimal version is just a floating-point number. In Perl decimal version can be represented by floating-point number, string, or version object:

    0.003010                        # floating-point number
    '0.003010'                      # string
    version->parse( '0.003010' )    # version object

Floating-point numbers can be compared, but lose trailing zeros. Strings do not lose trailing zeros, but string comparison operators are not suitable for comparing versions. version objects does not lose trailing zeros, can be easily compared, but cannot be modified.

See also: "Decimal Versions" in version::Internals.

Dotted Versions

Dotted (aka dotted-decimal) version is a series of parts joined with dots, each part is a cardinal (non-negative) integer. In Perl dotted versions can be represented by v-strings, strings, or version objects:

    v0.10.3                         # v-string
    'v0.10.3'                       # string
    version->declare( 'v0.10.3' )   # version object

V-strings can be easily compared (by cmp, eq and other string comparison operators), but are not suitable for printing. Strings can be easily printed but string comparison operators are not suitable for comparing versions. version objects can be easily compared and printed, but cannot be modified. (Version::Dotted objects can be.)

Leading 'v' character is optional: in strings — always, in v-strings — if there are two or more dots. However, using 'v' character is recommended for clarity and readability.

See also: "Dotted-Decimal Versions" in version::Internals.

Conversion Rules

To convert a decimal version to dotted one: (1) insert dot after each third digit in fractional part, and then (2) strip leading zeros in every part:

    1.003010 -(1)-> 1.003.010 -(2)-> 1.3.10

Obviously any possible decimal version can be conversed to corresponding dotted version.

To convert a dotted version to decimal one: (1) prepend each part (except the first) with leading zeros to have exactly 3 digits in each part, and then (2) strip all the dots except the first:

    1.3.10 -(1)-> 1.003.010 -(2)-> 1.003010

Not all dotted version can be converted to corresponding decimal one. First, all parts (except the first) of a dotted version must comprise not more than 3 digits. Second, dotted version should not contain too many parts due to limited precision of floating-point numbers.

Non-Stable Releases

Perl terminology in this area is not well-defined and not consistently used:

  • The version module declares any version with underscore character (e. g. 'v1.2.3_4') to be an "alpha" version. version::Internals refers to CPAN convention "to note unstable releases with an underscore in the version string".

  • In turn, CPAN::Meta::Spec defines release status as one of: stable, testing, and unstable. Word "alpha" is used in the description of unstable release, while testing release is described as "beta". There is also requirement that stable release version should not contain underscore. (There is no requirement that unstanble and testing releases should contain underscore.)

  • site has section named "Developer Releases" which is about releasing "code for testing". Such releases should either have version with underscore or "-TRIAL" suffix.

  • meta::cpan site in the list of module releases shows "DEV" (which likely means "developer release") after versions containing underscore.

  • dzil tool has --trial command line option to build a "release that PAUSE will not index".

"Alpha" term used by version module (and some others) is a bad choice because it has strong association with "beta" and "release candidate" terms, which do not have any support by version.

"Trial" term sounds more neutral and generic: a trial release could be either "alpha", "beta", "release candidate", "unstable", "testing", or "developer release".




version is an official Perl module for declare and compare versions, it is recommended by Task::Kensho and used by Perl itself (package Assa v1.2.3; automatically assigns $VERSION variable an object of version class). Unfortunately, the module does not provide any method to bump a version.

Perl::Version is another module recommended by Task::Kensho. This module provides method(s) to bump a version, e. g.:

    my $v = Perl::Version->new( 'v1.2.3' );
    "$v";   # eq 'v1.2.3_01'

I used such code with no problem… until version 0.9913. version 0.9913 changed interpretation of underscore character: before 'v1.2.3_01' was interpreted as 'v1.2.3.1' (+ trial flag, of course), starting from 0.9913 it is interpreted as 'v1.2.301' (+ trial flag).

I believe there were good reasons for this change (e. g. current version behavior matches Perl behavior and so reduces the mess), but this change breaks Perl::Version as well as my code because

    version->parse( 'v1.2.3_01' ) < 'v1.2.4'

was true before, is false now.

Thus, Perl::Version is broken and it is not clear when and how it will be fixed. But

  1. I want a method to bump a version, and want it now.

  2. I want a method to represent trial versions, and want it is compatible with version either pre-0.9913 or post-0.9912 (i. e. >= 0.77).

  3. I want these methods to work with dotted versions, decimal versions are out of my interest.

(BTW: Requirement #2 effectively means that new method should not rely on underscores.)

Version::Dotted fulfills these requirements.



Parent class. It provides most of functionality, can work with decimal versions, but does not provide any modifiers. Release status depends on presence of underscore character in version.


An alternative to version. It works with both decimal and dotted versions, provides modification operations. Release status depends on presence of underscore character in version.


It provides authoring time subroutine to "increment module version numbers simply and correctly", works with both dotted and decimal versions, but it "no longer supports dotted-decimals with alpha elements".


It implements Semantic Versioning 1.0.0 with no changes (?). SemVer allows alphanumeric pre-release versions like '1.2.3-alpha1' and orders them properly: 1.2.3-alpha < 1.2.3-beta < 1.2.3. However, SemVer is not authoring time tool, it should be used in runtime also to provide correct ordering: version does not recognize properly pre-release alphanumeric versions.


Subclass implementing adaptation of Semantic Versioning, part of this distribution.


Subclass implementing odd/even versioning scheme, part of this distribution.


Van de Bugger <>


Copyright (C) 2017 Van de Bugger

License GPLv3+: The GNU General Public License version 3 or later <>.

This is free software: you are free to change and redistribute it. There is NO WARRANTY, to the extent permitted by law.