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

In moving from Perl 5.22.0 to 5.22.1 I noticed an anomaly using tobyink’s P5U module: p5u v <Module> still finds the module correctly, but in some (not all) cases the version number disappears. Under 5.22.0:

12:24 >p5u v Capture::Tiny Capture::Tiny C:\Perl\Strawberry\strawberry-perl-5.22.0.1-64bit-PDL\perl\ven +dor\lib\Capture\Tiny.pm: 0.30

But under 5.22.1:

12:27 >p5u v Capture::Tiny Capture::Tiny C:\Perl\Strawberry\strawberry-perl-5.22.1.1-64bit-PDL\perl\ven +dor\lib\Capture\Tiny.pm: undef 12:27 >

Some tortuous debugging1 eventually led to sub version in Module::Info as the source of the version number. Furthermore, the problem was introduced between version 0.35 (which happens to be the version of Module::Info on my 5.22.0 Perl installation) and version 0.37 (the version on my 5.22.1 installation). But sub version didn’t change between those versions, so what did?

1Cue The Long and Winding Road.

These lines appear near the head of the code for Module::Info 0.35:

use vars qw($VERSION @ISA $AUTOLOAD); # quotes 'version' for 5.004 $VERSION = eval 'use version; 1' ? 'version'->new('0.35') : '0.35'; $VERSION = eval $VERSION;

In 0.37 this has changed to:

our $AUTOLOAD; our $VERSION; $VERSION = eval 'use version; 1' ? 'version'->new('0.37') : '0.37'; $VERSION = eval $VERSION;

And, yes, it turns out that the difference in behaviour does result from changing the declaration of $VERSION from use vars to our. Specifically, it’s a problem of scope: use vars (if I understand it correctly) creates a dynamic scope within the current package, whereas our creates a lexical scope that crosses packages within the same file.

Anyway, I came up with a short script that reproduces the problem I’m seeing in Module::Info:

use strict; use warnings; package Package_One; use vars qw( $VERSION ); #our $VERSION; $VERSION = 'irrelevant'; # "our $VERSION" comes from the target module; without "our" there's n +o problem my $eval =<<'END_EVAL'; no strict; local $VERSION; $VERSION=undef; do { our $VERSION = 'desired_version'; }; $VERSION END_EVAL printf "Version: %s\n", Package_Two->_eval($eval); package Package_Two; sub _eval { eval $_[1]; }

This script works correctly: it prints Version: desired_version. But when I change the declarations:

#use vars qw( $VERSION ); our $VERSION;

the version comes back undefined. Note that this problem goes away if the our inside the do block is removed from $eval:

my $eval =<<'END_EVAL'; no strict; local $VERSION; $VERSION=undef; do { $VERSION = 'desired_version'; }; $VERSION END_EVAL

— which explains why some modules have the version problem and some don’t: the former have their own package variable $VERSION declared with our, the latter do not.

So, my questions:

  1. Am I correct in thinking that this is a bug in the newer version of Module::Info?
  2. What role does the do block play in this? If I remove it, the problem seems to go away — but I can’t advocate just removing it, as I don’t understand what it’s there for in the first place. :-(
  3. I have “fixed” my local copy of Module::Info by changing our $VERSION back to use vars qw( $VERSION ), but should I recommend it as a patch? Or is there a better fix which retains the our declaration?

I’m posting here before submitting a bug report because I would like to first understand exactly what is happening, and why. Any insight or advice will be appreciated — especially an explanation of how the do block interacts with the surrounding code when it’s evaled. A step-by-step description of which $VERSION is which inside sub _eval would be very helpful, too. :-)

Thanks,

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

Replies are listed 'Best First'.
Re: Bug in Module::Info? our vs. use vars (local our)
by Anonymous Monk on Jan 16, 2016 at 08:22 UTC

    update: local our works

    my $eval =<<'END_EVAL'; no strict; local our $VERSION; $VERSION=undef; do { $VERSION = 'desired_version'; }; $VERSION END_EVAL

    I think its like doing  my $foo; { my $foo; } the inner foo is invisible

    Maybe see 'our' is not 'my' , local our $var; What does it do?

      local our works

      Yes, it works without warnings provided there is no our inside the do block. But that our comes from the external module being examined (Capture::Tiny in my examples), and when that our is present a warning is generated:

      18:47 >perl 1513_SoPW.pl "our" variable $VERSION redeclared at (eval 1) line 4. (Did you mean "local" instead of "our"?) Version: desired_version 18:47 >p5u v Capture::Tiny Capture::Tiny "our" variable $VERSION redeclared at (eval 49) line 7, <MOD> line 6. (Did you mean "local" instead of "our"?) C:\Perl\Strawberry\strawberry-perl-5.22.1.1-64bit-PDL\perl\ven +dor\lib\Capture\Tiny.pm: 0.30 18:47 >

      Thanks for the links. I’ve read 'our' is not 'my'; local our $var; What does it do? is interesting, but local our wouldn’t be suitable as a patch, anyway, because (judging by the use 5.006 pragma) Module::Info is intended to be backwards-compatible as far back as Perl 5.6.

      Cheers,

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

        :) solution is simple, eliminate any "our", don't do "our" in inner blocks of eval, our $VERSION; local $VERSION; is adequate, you don't have to use local our $VERSION;