http://www.perlmonks.org?node_id=11103877

A question came up here recently where a user wished to specify a minimum version for a parent class. base doesn't support specifying minimum versions, nor does parent. base and parent are core Perl modules. I don't think it would be appropriate to add complexity to the core Perl parent by adding this feature.

Perl facilitates setting minimum versions in use statements:

use Time::HiRes 1.9;

use has a compiletime effect, so that code behaves like this:

BEGIN { require Time::HiRes; Time::HiRes->VERSION(1.9) Time::HiRes->import }

However, BEGIN blocks require us to consider the order of loading more than we may want to. This doesn't fit the model of keeping simple things simple, if the simple thing we want to do is fairly common.

For inheritance we can do this:

package MyAgent; BEGIN { require LWP::Usergent; LWP::UserAgent->VERSION(6.39); # Assert a minimal version. push @MyAgent::ISA, 'LWP::UserAgent'; }

To me that's too much boilerplate for a common need. Another way:

package MyAgent; use parent 'LWP::UserAgent'; BEGIN {LWP::UserAgent->VERSION(6.39)}

But that's a little fragile; someone may refactor and forget to keep the BEGIN block after the call to parent causing things blow up. Sometimes code becomes complex, masking simple mistakes. I would prefer a solution that doesn't require the user to maintain several steps to set up inheritance while assuring minimal versions for parent classes.

parent::versioned makes the inheritance and compile-time version checking more convenient, and harder to get wrong. I uploaded it to CPAN a few hours ago.

package Myagent; use parent::versioned ['LWP::UserAgent' => 6.39];

parent and parent::versioned behave the same for all import lists unless an element in the import list is an array ref. Any array ref passed to the import list will be treated as a tuple that specifies a module name, and a minimum version for that module. Multiple inheritance works like this:

use parent::versioned ['LWP::UserAgent' => 6.39], ['Mojo::DOM' => 7.2 ], 'Foo::Base';

This example sets up triple inheritance: two modules that are version checked, and one that is not. As with parent, parent::versioned accepts the -norequire flag.

The parent module has 100% code test coverage. parent::versioned passes the parent test suite and maintains 100% coverage. It should work as a drop-in replacement for parent, but with the additional functionality exposed by passing an array-ref as part (or all) of the import list. Most of the code is a direct fork from parent. You can use it just like you use parent:

use parent::versioned qw(Foo);

I prefer keeping the module small, but if you're interested please do look at the GitHub repository. Patches, issues, and suggestions are welcomed. I hope it becomes useful.


Dave

Replies are listed 'Best First'.
Re: parent::versioned supports minimum version specification in parent classes
by talexb (Chancellor) on Aug 05, 2019 at 19:03 UTC

    Wow -- this is excellent. Thanks for writing this up, based on my original question.

    I think I just found a cool topic for a mini-presentation at the next Perlmongers meeting. :)

    Alex / talexb / Toronto

    Thanks PJ. We owe you so much. Groklaw -- RIP -- 2003 to 2013.

      Hope to be there...

Re: parent::versioned supports minimum version specification in parent classes
by jcb (Parson) on Aug 30, 2019 at 03:47 UTC
    Another way:
    package MyAgent; use parent 'LWP::UserAgent'; BEGIN {LWP::UserAgent->VERSION(6.39)}

    But that's a little fragile; someone may refactor and forget to keep the BEGIN block after the call to parent causing things blow up. Sometimes code becomes complex, masking simple mistakes. I would prefer a solution that doesn't require the user to maintain several steps to set up inheritance while assuring minimal versions for parent classes.

    I only now noticed this and must ask: how does this scenario cause things to blow up? Someone moving the BEGIN to before use parent? Even the most basic tests should catch that immediately.

    TIMTOWDI:

    use LWP::UserAgent 6.39; use parent 'LWP::UserAgent';

    That makes an extra require but perl will check %INC, see that LWP::UserAgent has already been loaded, and proceed quickly. Normal style is that object-oriented modules export nothing, so the implicit ->import call should be harmless.

    I believe that parent::versioned is the kind of feature that really does belong in the core or not at all — the TIMTOWDIs for it are just too simple to justify another dependency from CPAN for serious work, and it is the kind of feature that non-serious work does not care about.

Re: parent::versioned supports minimum version specification in parent classes
by Anonymous Monk on Aug 05, 2019 at 09:16 UTC

    We can arrange for approximately equi

    thats the beginning of .. Get rid of that

      I'm not sure what is being requested in this comment. Get rid of the post? The module? That wording? Some concept expressed in the post? Some goal for the module?

      I would appreciate feedback that is clear and actionable, and that comes in the spirit of patient, constructive criticism.


      Dave

        We can arrange for approximately equial... ,P.

        The quote is the beginning of some kind of infomercial type justification for writing parent::versioned, you dont need it

        ALso, name seems a tad long, parent::v or parent::mv ...