Breaking users of old versions of a module
Suppose that for some reason you really, really need to introduce a silent, backward-incompatible change for a module. For example, in 0.03 and earlier foo() accepts ($a, $b) as arguments but you need to change it to ($b, $a). After releasing v0.04, you probably also want to break code that says any of the following:
use MyModule; # no version specified
use MyModule 0.01;
use MyModule 0.02;
use MyModule 0.03;
by, e.g., croaking with a message like "Order of arguments of foo() changed in 0.04, please use older version or update your code. Program aborted."
Reading up on "perldoc -f use" and browsing on CPAN, I found version::Limit which does almost that. You can put something like this in MyModule.pm:
use version::Limit;
version::Limit::Scope(
"[0.0,0.4)" => "Order of arguments of foo() changed in 0.04",
);
version::Limit works by installing a VERSION() method into your module's package. This method is called by Perl when user is use-ing some module with a version requirement. But unfortunately, if user does not specify explicit version requirement, VERSION() will not be called.
If the change is backward-incompatible enough, you probably want to break use MyModule; (loading a module without version requirement) too.
One of the ways to do this is to also install the version checking routine into import(). But perhaps there are better ways?
One technique would be something like:
That way, if your caller imports your module as:
... they get the 1.x behaviour, but if they import it as:
... then they get the 2.x behaviour.
If your module is an exporter, better would be to use something like a Sub::Exporter-style generated sub; so the caller can elect which version of foo they wish to import. And if your module is OO, better would be to create a new method with a different name, and make the old foo an alias with different argument order:
Within
foo
you could also do something like:Yes, I've never disagreed that maintaining compatibility with old versions (for a while) is important.
But let's suppose again that we want to do a clean cut and remove old code/interface :-)
VERSION would be called before import, so you can flag whether it was or not:
[Wow, the preview always has the code formatted strangely no matter what combination of tags I try. Oh, well. You can see the point.]
You could also have multiple implementation modules behind the scenes, and pick which one to back onto based on the version specified when use'ing the module.
I guess that's a cleaner approach to me, by not cluttering the module with conditionals.
Thanks Toby & Neil.
Thanks, xdg. I've just released a proof of concept on CPAN: version::Restrict using ideas from here.
xdg: I think the trick to getting good formatting for code in the comments here is to make sure there are not any blank lines between
<pre>
and</pre>
. If you need a blank line, just make sure it's got a couple of spaces on it.