David,

Using a variant of that, we could let the undocumented 1.95 interface result when doing

  use Text::Balanced;        # or
  use Text::Balanced 1.95;

so that existing code will not be broken any more than it is. However, the new interface can result when doing

use Text::Balanced 2.00;

Further, both interfaces may be used simultaneously in the same program as such:

use Text::Balanced 2.00, qw(extract_quotelike);

  package Two;
  use Text::Balanced 1.90, qw(extract_quotelike);
  my $res = (extract_quotelike('asdf'))[0];
  print defined($res) ? "[$res]" : '(undef)';  # prints '[]'

  package main;
  my $res = (extract_quotelike('asdf'))[0];
  print defined($res) ? "[$res]" : '(undef)';  # prints '(undef)'


Here is the basic solution:


==========Text/Balanced.pm===========

use vars qw { $VERSION @ISA %EXPORT_TAGS %my_vers $caller};
$VERSION = '2.00';
@ISA = qw ( Exporter );

sub import
{
    foreach (@_) { $my_vers{caller()} = $1 if(/^(\d+); }
    Text::Balanced->export_to_level(1, @_);
}

sub VERSION
{
    my $req_ver = $_[1];
    $req_ver < 1.87 and
        croak "Text::Balanced $VERSION is incompatible with the requested "
            . "version $req_ver.";
    $req_ver > $VERSION and
        croak "Text::Balanced $VERSION is older than the requested "
            . "version $req_ver.";
    return $req_ver;
}

sub _fail
{
    ...
    return (undef,$$textref) if $my_vers{$caller} == 2;  # new style
    return ('',$$textref,'');    # old style (v. 1.xx)
    ...
}

sub extract_quotelike (;$$)
{
    ...
    $caller = caller() unless caller() eq 'Text::Balanced';
    ...
    return _fail($wantarray, $textref) unless @match;
    ...
};

sub extract_multiple (;$$$$)
{
    $caller = caller() unless caller() eq 'Text::Balanced';
    ... # this can call extract_quotelike()
    ...
}

===========================

The complexity with using caller() is needed unfortunately since the module has a functional interface. I'll think this solution over some more since I have doubts that the added correctness with existing code is worth making new code potentially more brittle.

A simpler solution would be to just croak if a 1.95 or prior version is specified in "use" and possibly carp or croak (probably carp) if *no version* is specified. That comes with its own small issues of course.

-davidm

david wrote:
Vagn Johansen wrote:

How are interface changes handled on CPAN?


They're not. I'm trying to promote a pradigm of including a VERSION subroutine that
will croak (or at least die) when you ask for a non-forwards-compat. version.


In theory, you change the name when you change the itnerface, instead of merely
updating the version number.


How do you avoid breaking old programs when the interface changes?


Issue a new module name with the new interface, and maintain both versions for bugs.




Reply via email to