http://qs321.pair.com?node_id=506839

I was recently burned by unintentionally breaking backwards compatibility with Perl 5.6 by using use Exporter 'import' rather than adding Exporter to the @ISA array. I realized that I don't have a very systematic approach to coding for backwards compatibility, which got me wondering about what else I should be mindful of and how others handle this problem.

I know about several well-known limitations, of course, e.g.:

And I know some less well-known limitations (at least, I don't see them mentioned often, so I'm guessing they're less well known), e.g.:

I wish I had an encyclopedic knowledge of the delta files: perl58delta, perl56delta and so on. The ideal, of course, would be something like RFC: perlfeaturedelta going back for several versions of Perl. (Joost -- did you ever take that further?)

However, in lieu of something that exhaustive being available, I'd love to hear from fellow monks about their real-life experiences and practices.

Some questions for discussion:

-xdg

Code written by xdg and posted on PerlMonks is public domain. It is provided as is with no warranties, express or implied, of any kind. Posted code may not have been tested. Use of posted code is at your own risk.

Replies are listed 'Best First'.
Re: Writing for backwards compatibility
by merlyn (Sage) on Nov 08, 2005 at 20:58 UTC
Re: Writing for backwards compatibility
by friedo (Prior) on Nov 08, 2005 at 18:54 UTC
    If requirements don't dictate a version of Perl to target, what version do you target when writing code for reuse?

    I generally target 5.6. It is probably the most widely installed perl these days and I have never been in a situation (yet) where I absolutely needed a 5.8 feature. Indeed, I don't know that I've ever absolutely needed a 5.6 feature, but things like lexical filehandles, our instead of use vars, etc. are rather convenient.

    Put differently, what features are you willing to give up for backwards compatible code?

    I'm not willing to give up much beyond Perl 5.6. IMHO, 5.6 is really the time when Perl 5 became a mature, "stable" programming language. 5.8 is a great accomplishment but it's not as big a milestone was 5.6 was.

Re: Writing for backwards compatibility
by dragonchild (Archbishop) on Nov 08, 2005 at 19:06 UTC
    <nit>3-arg open was added in 5.005_03, not 5.6.</nit>

    Update: Don't you just hate being completely and thoroughly being proven wrong? I do ... :-/

    I've just spent a while rewriting Tree::Simple into Tree and reworking PDF::Template. After discussion with stvn, we decided to require 5.6 as a minimum Perl version. We don't see a lot of benefit in attempting to maintain compat with anything before that.

    In our work, we target 5.8.6 as a minimum. For one thing, Unicode is handled much better (though not perfectly) in 5.8, which is nice. As for other features, it's nice to know that one has a better toolbox to reach for, even if one doesn't use them on a regular basis (or ever!)

    Other languages have the same issue. For example, in JS, there's no reason to target anything under 1.5 - all modern browsers implement 1.5 (for some value of "implement") and attempting to write JS for pre-1.5 is an exercise in baldness. Ruby is the same way - 1.8 is the modern version, so I target it. (Ruby's dbi is written under 1.6, which makes it throw warnings under 1.8 - very annoying!)


    My criteria for good software:
    1. Does it work?
    2. Can someone else come in, make a change, and be reasonably certain no bugs were introduced?
Re: Writing for backwards compatibility
by eyepopslikeamosquito (Archbishop) on Nov 08, 2005 at 23:39 UTC

    Your question is broader than Perl version: one also needs to choose what environments the code should work in. You may choose, for example, to target *nix and Windows only, so as to simplify the code (e.g. can use / as path separator without going to the bother of hauling in File::Spec).

    My biggest beef is that many authors seem to not consciously, explicitly and clearly state their module's version and environment requirements in the module's documentation. In addition to the documentation, they should enforce it programmatically -- with require 5.005_03, for example.

    Which Perl version and environment to target depends largely on the type of module. For example:

    • At work, where I can precisely control the Perl environment, I generally target perl 5.8.7+, *nix and Windows only. That allows me to learn and leverage the latest Perl features and simplify the code.
    • For CPAN modules, it's different. Modules that are expected to be needed in a broad variety of environments, such as Test::More, should target pre-historic Perl versions and all Perl environments. "Developer" modules, on the other hand, such as Devel::Cover, may reasonably choose to target only recent perl versions. You need to decide who the target users of the module are and whether it's reasonable to ask them to upgrade to a later perl version in order to use your module.

    Update: As for testing for backwards compatibility, I install a standard perl 5.005, perl 5.6, perl 5.8 on my development system (with no extra modules). Then, before uploading my CPAN module, I run a little script to unpack the tarball and run "make test" against all these versions. More elaborate automated schemes are obviously possible, but this straightforward test should catch most backward compatibility (and dependency) blunders before you upload the module.

Re: Writing for backwards compatibility
by etcshadow (Priest) on Nov 09, 2005 at 03:20 UTC
    Speaking as someone who is (at least currently) tethered to 5.005_03, I've got to speak up for how utterly annoying it is to find modules out there that needlessly use fairly pointless new features (specifically our, but also, to a certain extent use/no warnings).

    Don't get me wrong, lexical filehandles and 3-arg open are hugely nice, and I can't really argue with that. But how many modules out there just use our for no reason whatsoever, other than to force perl 5.5ers to have to edit the module before using it?

    ------------ :Wq Not an editor command: Wq

      I think 'our' is often used to avoid having to type 'use vars', but I recently saw a module on CPAN with a surprisingly obvious way of avoiding it. (strict police may want to avoid reading further.)

      package My::Module; $VERSION = 1.23; @ISA = 'Exporter'; @EXPORT = qw( wibble wobble ); use strict; use warnings; use Exporter; # rest of module ...

      -xdg

      Code written by xdg and posted on PerlMonks is public domain. It is provided as is with no warranties, express or implied, of any kind. Posted code may not have been tested. Use of posted code is at your own risk.

        Also, the third edition of Programming Perl describes the vars pragma as "somewhat deprecated". Current Perl docs don't label it that way...

        --
        Marvin Humphrey
        Rectangular Research ― http://www.rectangular.com

      When that happens, do you report test failures (using cpantest, provided by Test::Reporter)? If you do, I am pretty sure most authors will gladdly fix the code. Especially if you also include the patch. I am sure most authors do not willingly break compatibility, it just happens, sometimes for good reasons (unicode), sometimes just by habit or oversight.

      But how many modules out there just use our for no reason whatsoever, other than to force perl 5.5ers to have to edit the module before using it?

      I don't use our for no reason. I use it because I find it clearer and I have to type less.

      Unfortunately my priorities (typing less) do not match your priorities (working code on 5.005_3) :-)

Re: Writing for backwards compatibility
by Animator (Hermit) on Nov 08, 2005 at 21:06 UTC

    The following list is a (small) list of things that I know that work on 5.8 but not on 5.6.

    • An lvalue subroutine that ends with $obj->$sub("x") (the name of the method is a variable) does not work on 5.6.1. It does work fine on 5.8. (One of the many alternatives: $obj->can($sub)->($obj, "x");)
    • Using the internal PerlIO_close function (via XS/C) on an already closed file results in a segmentation fault on 5.6.
      Actually I consider this good... I experienced this with a module on CPAN. The module itself was doing the wrong thing (Closing files it didn't open, not incrementing the reference counter of the filehandle it was passed, ...). Yet noone using 5.8 noticed it...

    To answer some of your other questions:

    My default perl is 5.6.1. (I have others versions installed aswell). So when I write code it is (and I want it to be) backwards compatible with 5.6.1. And I will always do that. Even if I know for sure that it will be used only on 5.8.

    Letting go of features... I guess most of the new features of 5.8. I definitely won't let go of the 3-args open or my.

    The biggest thing that annoys me is a module that requires a specific version of Perl... Yes there might be a reason for it but atleast mention it somewhere in the POD... Someone might know an easy workaround... (Or a hard workaround if they really want to use it on an earlier version)

Re: Writing for backwards compatibility
by adrianh (Chancellor) on Nov 09, 2005 at 12:31 UTC
    If requirements don't dictate a version of Perl to target, what version do you target when writing code for reuse?

    I usually target the last three stable releases, unless requirements point me in another direction. So currently the earliest I worry about for my modules is 5.8.5.

    Put differently, what features are you willing to give up for backwards compatible code?

    Unless the requirements force me to, I'm usually not willing to give up features. In most cases I've found it more effective to spend the effort to get the requirements changed rather than stop using features I find useful.

    What features/code/modules that break compatibility do you most frequently encounter or have burned you the most, particularly when other, compatible methods would do just as well? (In your own coding or on CPAN)

    I guess the one that causes me the most pain, since I can't use Test::Class without them, is the lack of attributes in earlier Perl's.

    What workarounds or practices do you use to help with backwards compatibility?

    Unless it's forced by the requirements - I don't :-)

Re: Writing for backwards compatibility
by snowhare (Friar) on Nov 12, 2005 at 16:45 UTC
    * If requirements don't dictate a version of Perl to target, what version do you target when writing code for reuse?

    Depends on whether or not it is targeted for CPAN. I try to reach all the way back to 5.005 in my CPAN modules, if possible. In-house, 5.6 is the current target.

    * Put differently, what features are you willing to give up for backwards compatible code?

    I haven't really had to give up any significant features yet. Generally speaking, you can usually code 'around' anything that isn't targetted to a specific level of Perl in the first place (such as an 'Encode::*' module) or limitted by needed infrastructure (required modules that themselves can't be run on less than a certain version of Perl). But I have both 5.6.2 and 5.8.6 installed on production boxes so I can use a required version if necessary.

    * What features/code/modules that break compatibility do you most frequently encounter or have burned you the most, particularly when other, compatible methods would do just as well? (In your own coding or on CPAN)

    Most frequently it is gratuitious use of 'require 5.008001;' type perl version requirements in test suites caused by using autogenerated stubs. If your code doesn't explicitly need something only available in a certain version of perl or later, don't do it.

    What workarounds or practices do you use to help with backwards compatibility? (e.g. IO::String or IO::Stringy for "in-memory" files

    Depends on the target. For 5.005 I avoid 'use warnings' in favor of 'local $^W = 1;' invokations and use 'local' instead of 'our'. For 5.6, I avoid 'Encode' and use 'Unicode::MapUTF8' instead.