Discussions about module versions have touched on questions of how to
distinguish or specify interfaces/APIs a few times, but I haven't
seen much detail, so I thought I'd post some musings on the subject.
At its simplest, I want to add some functionality to my program by
using some module; and plenty of p5 code is just that simple. But I
might also want to specify a version number so I don't end up with
some obsolete version of the module that won't work with my program.
And higher version numbers are (in general) assumed to be better, so
I don't want to limit my code to using just the module that happened
to be available when I wrote it; I need to specify some range of
versions, e.g. "v1.2.3 or higher", to try to catch any improvements
from future releases (or just to catch the availability of later
releases, in case the older version isn't installed).
S11 gives us wildcards and smart-matches to do this sort of thing:
use Foo::Bar-(1.2.3..^2.0 | 2.6...). But if v1.2.3 is the cutting
edge when I write my program, I don't know that v2.0 is going to
throw out a bunch of deprecated methods, nor that v2.6 is going to
bring them back because of overwhelming popular demand. So I have to
ask myself do I feel lucky? Or am I going to update my code every
time one of its modules is updated (not to mention other people who
might be using my program)?
What I really want to do is specify, "I wrote this code according to
version 1.3.1 of the FooBar API" and have Perl pick any module that
claims to satisfy that spec. After all, the module should know what
version of the API it offers. If Smith updates his Foo::Bar module,
he knows whether the interface has changed and his module can say so.
Of course, I still want to be able to specify version numbers as
well, so for example I can say, "use [API] FooBar-1.3.1, but don't
use particular version SMITH-2.3.4" (because I happen to know that
it's buggy, even though it advertises itself as filling the API I
requested). In general, though, a program would ask for modules that
provide the specific interface that it was written for, and expect to
get the highest version available for that API.
Which version is the highest is a more complicated question when
different people are writing modules for the same API. I guess if
Jones writes a module that he considers better than Smith's version
SMITH-2.5, Jones can just call his version JONES-2.6 (even if his
previous version was only JONES-0.5).
The author[ity]'s name itself is really just part of the version, I
guess (or a separate dimension of versionality -- if the version
number defines the version across time, then the author represents
the version across space). But the whole version number-and-name can
be considered separate from the interface name. The API name should
stay the same, because it doesn't change. Thus it shouldn't matter
whether multiple people are writing module versions, or whether Jones
takes over maintenance of Smith's module. The versions might change
from Foo::Bar-SMITH-2.5 to Foo::Bar-JONES-2.6, but the API will still
just be Foo::Bar, and so my code doesn't care.
Well, if there's more than one API that wants to call itself
"Foo::Bar", we can add an author and call it Foo::Bar-SMITH, and it
doesn't matter if Jones takes over one day. Jones's *versions* could
have his name, but the API would always be Foo::Bar-SMITH because
Smith invented it.
Actually, the API name can be anything, as long as it's unique.
Whether it's worth defining parts like number and author (inventor?),
etc. the same way we do for versions, I'm not sure. Having a
well-defined structure is beneficial only if there's a use for the
separate parts. (E.g. we can pull out the "number" part of a version
to figure out which version is more recent than another.)
APIs would typically have some number in their name (e.g.
Foo::Bar-10.3, Foo::Bar-10.4), but unlike a version number, that's
not terribly useful to Perl (hm, is it?). Bigger is still probably
better to someone who's writing a new program, but for code that's
already written, it doesn't matter whether the API is slightly
different or completely different -- you can't simply substitute one
for the other. And while I would expect module writers to typically
use numbers to distinguish evolving APIs, you could just as well
label them Foo::Bar-Panther and Foo::Bar-Tiger if you wanted to.
Really, where I refer to 'versions' above, I should be saying
'implementation versions' as distinct from 'interface versions', but
I think (for today, anyway) that we don't care much what goes in the
API identifiers at all. The names don't even have to be explanatory
(it works for Theorem::Pythagoras) -- we could rely on the module to
supply a list of keywords to explain what it's for or to use in
searching.
-David
- Modular versions and APIs David Green
-