Google Groups no longer supports new Usenet posts or subscriptions. Historical content remains viewable.
Dismiss

Modular versions and APIs

0 views
Skip to first unread message

David Green

unread,
Dec 7, 2005, 4:06:55 AM12/7/05
to perl6-l...@perl.org
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

Larry Wall

unread,
Dec 8, 2005, 4:25:44 PM12/8/05
to perl6-l...@perl.org
It's probably not entirely clear in the spec, but it is already the
intent that version numbers work as API designators as well as module
designators. Certainly, as you speculate, if different authors want
to share an API, they can give it an "API" author that knows how to
delegate to one of the authors.

For the most part, however, I think people will use v1.2 as the API
and v1.2.3 as one particular module implementating the v1.2 API.
That was more or less why three part version numbers were invented,
after all. You'll note that we've been careful to define our matching
so that v1.2 requires an *exact* match on the specified part, so v1.2
does not match v1.3. It does, however, match any of v1.2.0, v1.2.1,
v1.2.3, up to v1.2.18446744073709551615 or so, plus any subversions
like v1.2.3.4.5.6.

Plus there's all the pattern matching, which lets you say (v1.2...)
if you really want that. Plus the fact that a v1.3 module is allowed
to advertise that it knows how to pretend to be the v1.2 interface,
though admittedly the syntax for that part isn't specced yet. In
any event, the module aliasing mechanism is expected to paper over
all those differences to the extent possible. I can say

use Penguin-1.2;

and within the rest of the *lexical* scope it aliases the short
name Penguin to whatever full name we really used, and that might
be actually be cobol:Dinosaur::Factory-42.582.17.255.255.0-DARWIN
or some such...

That probably covers most of your concerns. Improvements to the spec
always welcome...

Larry

Rob Kinyon

unread,
Dec 8, 2005, 11:16:52 PM12/8/05
to perl6-l...@perl.org
On 12/8/05, Larry Wall <la...@wall.org> wrote:
> [snip] Certainly, as you speculate, if different authors want

> to share an API, they can give it an "API" author that knows how to
> delegate to one of the authors.

Would you mind elaborating on this some more?

Thanks,
Rob

Larry Wall

unread,
Dec 9, 2005, 12:44:52 PM12/9/05
to perl6-l...@perl.org

I don't really have much elaboration to give. We have policy modules
that can invoke other modules on behalf of the user, and you can view
an API module as a kind of policy module.

We also already know that we need to figure out how to pick between

Funny-1.2-STAN
Funny-1.2-OLLIE

using something like a policy. Certainly one way to handle that would
be to allow whomever is making the decision to create a

Funny-1.2-API

that picks between ABBOT and COSTELLO, as a kind of editorial decision.

There are two elaborations on this theme. One is that

use Funny-1.2

could be considered a request to search for

use Funny-1.2-API

or more likely

use Funny-(1.2.0...)-API

or even

use Funny-(1.2.0...)-(/^.* _API$/)

The second is that "API" if API here is representing some kind of
editorial selection, there are potentially multiple editorial entities,
and they would presumably have different names.

use Funny-(1.2.0...)-USER_API
use Funny-(1.2.0...)-SITE_API
use Funny-(1.2.0...)-CPAN_API
use Funny-(1.2.0...)-RH_API
use Funny-(1.2.0...)-MS_API
use Funny-(1.2.0...)-G_API
use Funny-(1.2.0...)-K_API
use Funny-(1.2.0...)-MOD_API
use Funny-(1.2.0...)-ECMA_API

and then

use Funny-(1.2.0...)-API

might actually be end up looking for

use Funny-(1.2.0...)-(/^ $THEME _API $/)

and then we get to fight over who sets $THEME.

On the other hand, it can reasonably be argued that a "true" API should
be completely agnostic as to its implementation. On the gripping hand,
with roles we are specifically giving our interfaces the right to
specify default implementation, and this is construed as a feature.
So maybe it's okay for an API to specify its default. In fact, arguably
it should be *required* to specify its default so there's clarity about
who has to add more authorial information and who doesn't.

But this is all probably something the CPAN folks would do a better
job designing, not me. I just wanted to point out the underlying
principle that version numbers are like array indices and authors are
like hash keys, and that sometimes you want to have ordered versioning,
and sometimes you don't. But then we have to give users a way to sort
the hash keys.

Hmm, I guess I had more to say about that than I thought I did.

Larry

0 new messages