Beefy Boxes and Bandwidth Generously Provided by pair Networks
Perl Monk, Perl Meditation
 
PerlMonks  

parent::versioned supports minimum version specification in parent classes

by davido (Cardinal)
on Aug 04, 2019 at 18:58 UTC ( #11103877=perlmeditation: print w/replies, xml ) Need Help??

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.

A reply falls below the community's threshold of quality. You may see it by logging in.

Log In?
Username:
Password:

What's my password?
Create A New User
Domain Nodelet?
Node Status?
node history
Node Type: perlmeditation [id://11103877]
Front-paged by haukex
help
Chatterbox?
and the web crawler heard nothing...

How do I use this? | Other CB clients
Other Users?
Others meditating upon the Monastery: (4)
As of 2023-09-29 00:55 GMT
Sections?
Information?
Find Nodes?
Leftovers?
    Voting Booth?

    No recent polls found

    Notices?