I like what Version::Split is attempting to do (triggering a compile time error if a newer version of a module could result in logic errors) and how it does it (overriding the VERSION method). Perl6 RFC78 seems to address a different but related problem (selecting a module from multiple installed versions) which requires a different solution (modifying "require" to scan the library path differently). In fact, both efforts might be combined.
Anyway, a few comments though on the Version::Split POD document...
(1)
A change that is neither an interface change nor a behavioral change is not necessarily a bug fix. The change could be a huge internal refactoring (e.g. complete rewrite for better maintainability). Assigning the original code the version+revision "1.3.2 67" and the new code "1.3.2 68" does not reflect the magnitude of the change. If I am the user of "1.3.2 67" and I see that "1.3.2 68" is now available, would I bother to upgrade? Probably not--the difference appears inconsequential from the version+revision number alone.
(2)
>Consider what happens when you have extended your interface several times and >your version is now 1.2.3.4 . This is getting a bit long so maybe it's time to > make a clean break and call it 1.3 or even 2.
This may be a quirky part in the design. It makes me question whether it is useful for the relationship between 1.2.3 and 1.2.3.1 to be implicit at all in the numbering scheme since *in the general case* it it not possible for the module users to deduce the relationship from the numbers alone (e.g. 1.2.3 v.s. 1.3). If I see that 1.3 is now available, can I instantly tell from the numbers alone whether it will break my code that uses 1.2.3? No. Furthermore, the intuitive (but now possibly incorrect) understanding of 1.2.3 v.s. 1.2.3.1 is that the latter involves a very minor amount of code change.
The previous two points point out that version numbers are now being used for TWO things, neither well: (a) to (partly) describe the amount of code changes and (b) to (partly) describe interface/behavioral compatibility. I believe that one or the other should be chosen rather than both.
(3)
Version::Split is conservative (safe) in its detection of version incompatibilities, with a relatively low number of false negatives (theoretically zero though not in practice) and a relatively high number of false positives. That is, if Version::Split says that my code will remain compatibile with a new version of a module, it will most likely be correct. But if Version::Split says there is an incompatibility, there is a good chance it may be wrong. Case in point:
# Shape.pm v. 1.1
...
sub new { ... }
sub get_area { ... }
sub get_color { ... } # Shape.pm v. 1.2
...
sub new { ... }
sub get_area { ... }
sub get_colour { ... } # incompatible# myprogram.pl # Note: this code does not use get_color(), so it should also work with 1.2. use Shape 1.1; my $s = new Shape(); print $s->get_areas();
This fact is not necessarily bad but a tradeoff of generality v.s. complexity, something that could be documented in the POD.
-davidm
Fergal Daly wrote:
Sorry, here's the POD for Version::Split
NAME Version::Split - Flexible, useful and unambiguous version numbers
SYNOPSIS package My::Module; use Version::Split qw( 1.3.2 67 => 1.2 1.1 1 1.1 => 0.8 )
use My::Module 0.8; # will be ok if My::Module 1.3 is installed
DESCRIPTION
Version::Split allows you to require the interface version unambiguously and
separately from the revision (bugfix) version. It also allows you to declare
what other versions of the interface this version is compatible with.
This allows users who require the functionality of version x.y of your
module to simply require version x.y . You can continue to release new
version of your module and neither you nor your users need to worry about
incompatibilities between versions - as long as you make sure you correctly
change the interface version whenever you change the interface or behaviour
of your module.
If you want to make a release that doesn't change the behaviour - for
instance a bug fix release or to add some extra docs, then you simply change
the release version and leave the interface as it was.
USAGE Usage is quite simple. When you "use Version::Split" the first 2 arguments are the interface version followed by the revision version. After that you may declare some other interface versions that this module is compatible with. "use"ing this module will set $VERSION, $VERSION_INTERFACE, $VERSION_REVISION and %VERSION in the package that uses it.
So for example
package My::Module; use Version::Split qw( 1.3.2 67 => 1.2 1.1 1 1.1 => 0.8 )
means that this is version 1.3.2 of My::Module and release 67. It will set
"$My::Module::VERSION = "1.3.2_67"". It also says that version 1.3.2 is
compatible with 1.2, 1.1 and 1. Finally it says that 1.1 is compatible with
0.8, this information can be used to work out that 1.3 is also compatible
with 0.8.
So if someone does
use My::Module x.y;
where x.y is any of 1.3.2, 1.2, 1.1, 1 or 0.8 then the use will succeed. Also x.y.z is always considered to be compatible with x.y so anyone requesting 1.3 will also succeed.
If the version is anything else then the use will fail with an error message.
NOTE. The "qw()" after "use Version::Split" is very important. If you write
"()" you must include "=>"s. The reason for weirdness because of some
strange properties of unquoted version numbers and things that look like
version numbers, namely if you write 1.2.3 you don't get "1.2.3" you get
"\1\2\3" which is not very helpful. So rather than risk that, everything is
passed as quoted strings and Version::Split parses it a bit like a Perl hash
with the "=>" separators.
CHOOSING YOUR NEXT VERSION
Lets say you have just released My::Module 1.2 revision 5. Now you want to
add some clever new function to your module. You're not going to change any
of the old functions so you'll still be compatible with 1.2 . You have 2
choices.
You can extend the interface version number, calling it 1.2.1 for instance,
then it will automatically be considered compatible with 1.2 because it
starts with 1.2 and you're finished.
Alternatively you could call it 1.3 and then declare in the module that 1.3
is actually compatible with 1.2.
Why would you want the second option? Consider what happens when you have
extended your interface several times and your version is now 1.2.3.4 . This
is getting a bit long so maybe it's time to make a clean break and call it
1.3 or even 2. As long as you update the compatibility information there's
no problem.
Another example is where you create 1.2.1 and realise that you got the
interface slightly wrong. Maybe the function name is fine but you want to
change the order of the arguments. You could make this 1.2.2 because it's
still compatible with 1.2 and this is not considered compatible with 1.2.1.
NOTE Since 1.2.x is automatically considered compatible with 1.2, you must not call something 1.2.x if it is not compatible with 1.2 .
WHY MAKE LIFE SO COMPLICATED?
Because trying to use a single version number to track interface and release
version doesn't work. Even if you specify acceptable versions using <, =,
and ! (as Module::Build and only allow) then you still can't guarantee that
you will
* Avoid all future versions which are not compatible * Accept all future versions which are compatible and contain bug fixes
The fact that you can't achieve both of these goals means that if you are
the author if Your::Module then you should really be monitoring all releases
of all modules that Your::Module depends on and checking whether each one is
compatible, updating you dependency information accordingly and making
releases of Your::Module with nothing new in them except this dependency
information. This sucks big time.
If Your::Module depends on His::Module and His::Module is using
Version::Split then as long as He keeps the version info in His::Module
correct, You never have to worry about getting an incompatible version and
Your::Module will always accept newer revisions of His::Module which contain
bug fixes.
BUGS Because version strings are a bit like funny floating point numbers and I haven't had time to sort it out you must be careful not to leave any trailing 0s at the end of your versions so don't do
use Version::Split qw( 1.3.2 67 => 1.0 1.0 => 0.8 )
This will be fixed soon.
CPAN, CPAN.pm etc know nothing about this, maybe one day they will.
I need to add some way to require a minimum revision level of a given interface. It's easy but it's bed time now.
DEPENDENCIES
Test::More, Test::NoWarnings are required for testing, apart from that it's
independent.
HISTORY
Been thinking about this for a while, had a quick rant about it on the
module-authors mailing list, followed by a chat where the VERSION method was
pointed out.
http://www.mail-archive.com/[EMAIL PROTECTED]/msg01542.html
SEE ALSO Module::Build, ExtUtils::MakeMaker, only, version.
AUTHOR Written by Fergal Daly <[EMAIL PROTECTED]>.
COPYRIGHT Copyright 2004 by Fergal Daly <[EMAIL PROTECTED]>.
This program is free software and comes with no warranty. It is distributed
under the LGPL license. You do not have to accept this license but nothing
else gives you the right to use this software.
See the file LGPL included in this distribution or http://www.fsf.org/licenses/licenses.html.
