Beefy Boxes and Bandwidth Generously Provided by pair Networks
Perl: the Markov chain saw
 
PerlMonks  

The "right" way to make your script run with old versions of perl

by xorl (Deacon)
on Jun 08, 2016 at 15:11 UTC ( #1165148=perlquestion: print w/replies, xml ) Need Help??

xorl has asked for the wisdom of the Perl Monks concerning the following question:

Unfortunately we have some servers with perl 5.6 and 5.8 on them. I want my script to be able to still run with the older versions, but if it is running something newer I want it to use an efficient module. So basically I want to do something like:
if ($] > 5.010) { use Super::Cool::Module; $supercool = 2; } elsif (($] <= 5.010) && ($] > 5.008)) { use Almost::Cool::Module; $supercool = 1; } elsif ($] <= 5.008) { print "No module available for this ancient perl\n"; $supercool = 0; ## insert code here to duplicate the functionality of the newer module +s. } ### then later in the code if ($supercool == 2) { # do stuff with the super cool functions } elsif ($supercool == 1) # do stuff with the less cool functions } else { # 10000 lines of code to implement the super cool functions in ancient + perl. }
Is this really the best way to go? Just doing this psudocode here looks really messy to maintain.

Replies are listed 'Best First'.
Re: The "right" way to make your script run with old versions of perl
by Athanasius (Archbishop) on Jun 08, 2016 at 15:33 UTC

    Hello xorl,

    You can make this kind of code cleaner by taking an OO approach. Create an abstract class Module with the common interface, and subclass it as Module::SuperCool, Module::AlmostCool, and Module::Uncool. Then create a Module object once:

    use Module; use Module::SuperCool; use Module::AlmostCool; use Module::Uncool; my $module_instance = ($] > 5.010) ? Module::SuperCool->new(...) : (($] <= 5.010) && ($] > 5.008)) ? Module::AlmostCool->new(...) : Module::Uncool->new(...); ... $module_instance->frobnicate(...);

    and use it as needed — there will be no need for switch statements using a $supercool flag.

    Of course, Module::SuperCool will be implemented using super cool functions provided by cutting-edge CPAN modules; Module::AlmostCool will be implemented using less cool functions from older CPAN modules; and Module::Uncool will be implemented using your 10,000 lines of code.

    Hope that helps,

    Athanasius <°(((><contra mundum Iustus alius egestas vitae, eros Piratica,

Re: The "right" way to make your script run with old versions of perl
by Corion (Pope) on Jun 08, 2016 at 15:37 UTC

    Personally, I like to write multiple modules that all implement the same API, like the following:

    package Super::Cool::Perl5_006; # The most basic implementation
    package Super::Cool::Perl5_008; use Super::Cool::Perl5_006; # First import all the stuff from 5_006 # and overwrite some of the newer stuff
    package Super::Cool::Perl5_010; use Super::Cool::Perl5_008; # Not totally basic implementation

    The package Super::Cool then basically loads the appropriate implementation package and exports the subroutines into the calling package.

    This approach is great until you have a longer subroutine which has a common setup case and then one (or more) special cases after the common setup. My approach would then move the special handling into a separate subroutine, which makes the code more disjointed as the logic is then spread out over more subroutines. The alternative would be to copy and rewrite the subroutine for each Perl version, which carries its own hazards.

Re: The "right" way to make your script run with old versions of perl
by haukex (Bishop) on Jun 08, 2016 at 15:59 UTC

    Hi xorl,

    The other solutions so far by Athanasius, Corion and MidLifeXis are cleaner and easier to maintain, and I would also suggest wrapping the functionality in a module that abstracts your Cool modules. But just for completeness, here's one way to directly implement the code you've shown (untested Update: now tested, and fixed a bug):

    my $SUPERCOOL; BEGIN { if ( ($] ge '5.010') && eval("use Super::Cool::Module; 1") ) { $SUPERCOOL = 2 } elsif ( ($] lt '5.010') && ($] ge '5.008') && eval("use Almost::Cool::Module; 1") ) { $SUPERCOOL = 1 } else { $SUPERCOOL = 0 } }

    You don't even have to make the conditions dependent on the versions, you can just try to use several modules and take whichever one is available. And a note on $]:

    When comparing $], string comparison operators are highly recommended. The inherent limitations of binary floating point representation can sometimes lead to incorrect comparisons for some numbers on some architectures.

    Hope this helps,
    -- Hauke D

Re: The "right" way to make your script run with old versions of perl
by MidLifeXis (Monsignor) on Jun 08, 2016 at 15:38 UTC

    Perhaps something like this?

    package My::Interface::VersionBased; sub new { if ($some_condition) { return My::Interface::VersionBased::ForCondition1->new(@_); } elsif ($some_other_condition) { require My::External::Interface; return My::External::Interface->new( @_ ); } else { die "Unable to find a proper interface"; } }

    --MidLifeXis

Re: The "right" way to make your script run with old versions of perl
by afoken (Canon) on Jun 08, 2016 at 19:44 UTC
    Unfortunately we have some servers with perl 5.6 and 5.8 on them. I want my script to be able to still run with the older versions, but if it is running something newer I want it to use an efficient module. [...] Is this really the best way to go? Just doing this ps[e]udocode here looks really messy to maintain.

    I don't like that approach, for exactly that reason. Perl has excellent backwards compatibility. You don't have to rewrite all of your perl 5.005 scripts and modules just because your shiny new development machine features perl 5.40.98. They will run just fine, and probably quite efficient, perhaps even better than with the old perl version. There is a large perl code base, not only on CPAN, the Perl core developers are very aware of that fact, and try very hard not to break or drastically slow down old code.

    If you read the various perldeltas, you will find that nearly each new perl version increases speed for various parts of perl by improving algorithms or better fine tuning.

    use strict is just a tiny artefact of the backwards compatibility. Forcing strict mode on by default would be quite easy, but it would break old perl code. So you have to add use strict; to your new code. Same for use feature.

    So, if your code must run on perl 5.6, write it for perl 5.6. Avoid all features that require a newer perl. You will get a single, maintainable code base, no extra tricks required. And it will run good on 5.6, and perhaps slightly faster with each new perl version.

    One day, the last server running 5.6 will disappear, and you can define 5.8 as minimum, using the 5.8 features where you like. Wash, rinse, repeat.


    How do you define "an efficient module"?

    Lines of code required? I really don't care about that. Code is the least part of a project, easily burried under tons of documentation. (And documentation requirements get exponentially worse once you start working in medical or aerospace environments.)

    Time required to process a job? CPU usage for the job? Memory usage? Electric power usage? How do you measure that? How big are the differences? If the "efficient module" saves you a few nanoseconds, a few bytes, or a few microwatt-hours per job, seconds, megabytes, watt-hours per day, compared to the "inefficient module", you are doing it wrong. You are micro-optimizing somewhere deeply in the noise floor, below any sane measurement.

    Lines of code required to use a module? If it works great, but has a really garbage interface, write a thin wrapper that offers a sane interface to fix that once and forever.

    Alexander

    --
    Today I will gladly share my knowledge and experience, for there are no sweeter words than "I told you so". ;-)
Re: The "right" way to make your script run with old versions of perl
by choroba (Archbishop) on Jun 08, 2016 at 16:19 UTC
    Have a look at if if you don't want to
    eval "use $module";

    ($q=q:Sq=~/;[c](.)(.)/;chr(-||-|5+lengthSq)`"S|oS2"`map{chr |+ord }map{substrSq`S_+|`|}3E|-|`7**2-3:)=~y+S|`+$1,++print+eval$q,q,a,
Re: The "right" way to make your script run with old versions of perl (why?)
by BrowserUk (Pope) on Jun 08, 2016 at 21:38 UTC

    Personally, I think the correct answer is: Don't!

    Someone set up a 5.6 server 10 years ago and installed v1.x of XYZ that was available then, and it worked for them.

    A few years later someone (maybe the same someone) sets up a 5.8 server and installs v2.x of XYZ and it works for them.

    A few years on and someone (...) sets up a 5.14 server with version 3.x of XYZ and it works for them.

    You are writing version 4.0 of XYZ, and adding new features. Are you anticipating that the guys still running Perl v5.6 is going to replace his working installed version of XYZ with your latest code? Why would he do that? To make use of the new features, he would have to modify his code to use them.

    But this is a man still running a perl 5.6! It just doesn't seem likely he is going to modify anything. His existing code works; his installed XYZ v1.x still works. Why would he change?

    Ditto the others.

    The only reason I can see for doing what you're asking, would be if you've received a bug report for (say) the 1.x version and your intent is that the fix is to tell the guy to upgrade. Good luck with that :)


    With the rise and rise of 'Social' network sites: 'Computers are making people easier to use everyday'
    Examine what is said, not who speaks -- Silence betokens consent -- Love the truth but pardon error.
    "Science is about questioning the status quo. Questioning authority". I knew I was on the right track :)
    In the absence of evidence, opinion is indistinguishable from prejudice. Not understood.
Re: The "right" way to make your script run with old versions of perl
by xorl (Deacon) on Jun 15, 2016 at 18:13 UTC

    No one suggested my eventual "solution," so it is probably wrong. :(

    I realized just because the servers have 5.6 on them doesn't mean that something like 5.14 or even 5.20 can't be installed and run on them. So I installed perlbrew and told the person who needs to run the script to use have perlbrew use perl 5.18 to run the script. Other than some major annoyances with setting up perlbrew, it seems to be working well enough.

    If I did have to write something to run on the older Perls, I really like the ideas put forth by Athanasius and Corion. Also I guess BrowserUk came the closest with the "Don't do it" answer.

    Thanks again for the help

Log In?
Username:
Password:

What's my password?
Create A New User
Node Status?
node history
Node Type: perlquestion [id://1165148]
Approved by Ratazong
Front-paged by kcott
help
Chatterbox?
and the web crawler heard nothing...

How do I use this? | Other CB clients
Other Users?
Others lurking in the Monastery: (6)
As of 2021-04-17 17:16 GMT
Sections?
Information?
Find Nodes?
Leftovers?
    Voting Booth?

    No recent polls found

    Notices?