Question

I have just found a script we are using which has a sub that says my %INC in it, where it stores some values about incentives, thus %INC. This never seemed to be a problem, or no-one ever noticed. For me it produced 20 screens of redefine warnings, because %INC, holding all the file names Perl has done, required or used, was pretty large, and now is ('stuff' => 123).

Do I really have to go and rename every single reference to this in the sub, or is there another way to make Perl forgive this ... ?


Here's a part of the output of:

print Dumper \%INC; # I added this line
my %INC;             
print Dumper \%INC; # I added this line
exit;               # I added this line

Output:

          [...]
          'SqlConnect.pm' => 'lib1/SqlConnect.pm',
          'Lib/RateRequest.pm' => 'Lib/RateRequest.pm'
        };
$VAR1 = {};
[Fri Jun 29 16:09:13 2012] live_batch_test.pl: Subroutine export_fail redefined at /usr/lib/perl5/5.14.2/Carp.pm line 43.
[Fri Jun 29 16:09:13 2012] live_batch_test.pl: Subroutine _cgc redefined at /usr/lib/perl5/5.14.2/Carp.pm line 45.
[Fri Jun 29 16:09:13 2012] live_batch_test.pl: Subroutine longmess redefined at /usr/lib/perl5/5.14.2/Carp.pm line 51.
[Fri Jun 29 16:09:13 2012] live_batch_test.pl: Subroutine shortmess redefined at /usr/lib/perl5/5.14.2/Carp.pm line 71.
[...] (Snipped like 20 screens of redefine warnings)

The warnings only show if I create an object of one of my classes (which happens to contain SOAP::WSDL so it has a lot of stuff in it). I'm not sure why those are redefine warnings. If %INC is empty, how can it know stuff is being redefined?


Update:

It seems you actually can create a lexical my %INC.

use strict; use warnings; use Data::Dumper;
print Dumper \%INC;
{
  my %INC = ('asdf' => 'asdf');
  print Dumper \%INC;
}
print Dumper \%INC;

Produces (snipped):

          'feature.pm' => 'C:/Perl/lib/feature.pm'
        };
$VAR1 = {
          'asdf' => 'asdf'
        };
$VAR1 = {
          'warnings/register.pm' => 'C:/Perl/lib/warnings/register.pm',

The problem in my case does not seem to be the my %INC, but rather the %INC = &sub_that_has_my_percent_INC_and_returns_it() in the script that I actually have to require. Now that, in turn, also has use vars qw(%INC). Replacing it... well, I'm not sure what that is going to break.

Était-ce utile?

La solution

The global variable %INC (or %main::INC or %::INC) is a completely different variable from the lexically scoped %INC, created with my. You can safely use my %INC in your subroutine.

Autres conseils

Defining lexicaly scoped my %INC is possible, but this variable have absolutely no special meaning. Perl only considers global %INC when working with module system.

Your problem is elsewhere

Just to entertain you with examples, given:

Aaa.pm

package Aaa;
warn "Aaa loaded!";

1;

inc.pl

use strict;
use warnings;
use Data::Dumper;

use Aaa;
require Aaa;
warn 1, Dumper \%INC;
{
    my %INC;
    use Aaa;
    require Aaa;
    warn 2, Dumper \%INC;
}
warn 3, Dumper \%INC;
my %INC;
use Aaa;
require Aaa;

sub again {
    my %INC;
    require Aaa;
    warn 4, Dumper \%INC;
}

again();
warn 5, Dumper \%INC;

You will only see global %INC in 1 and 3, without whatever changes to lexical ones and Aaa.pm will still be loaded exactly once.

perldoc vars says that the vars pragma has been superseded by the our keyword.

Following the documentation's advice seems to work for me:

package Incentives;

use strict;
use warnings;
use Data::Dump 'dump';

our %INC = ( abc => 123 );

dump \%INC;                   # ( abc => 123 ),
                              # different under use vars '%INC';

use List::Util;               # Loads just fine

package Test;

use Data::Dump 'dump';

dump \%Incentives::INC;       # ( abc => 123 )
dump \%main::INC;             # reference to global %INC

1;

You'll have problems if you touch the global package variable %INC, but you can create all the lexicals named %INC you want and it won't be a problem.

$ perl -e'require CGI; my %INC; require CGI;'

$ perl -e'require CGI; local %INC; require CGI;'
Subroutine export_fail redefined at .../Carp.pm line 64.
Subroutine _cgc redefined at .../Carp.pm line 66.
Subroutine longmess redefined at .../Carp.pm line 72.
Subroutine shortmess redefined at .../Carp.pm line 92.
Subroutine croak redefined at .../Carp.pm line 100.
Subroutine confess redefined at .../Carp.pm line 101.
Subroutine carp redefined at .../Carp.pm line 102.
Subroutine cluck redefined at .../Carp.pm line 103.
Constant subroutine Carp::CALLER_OVERRIDE_CHECK_OK redefined at .../Carp.pm line 108.
Subroutine caller_info redefined at .../Carp.pm line 114.
Subroutine format_arg redefined at .../Carp.pm line 181.
Subroutine get_status redefined at .../Carp.pm line 213.
Subroutine get_subname redefined at .../Carp.pm line 222.
Subroutine long_error_loc redefined at .../Carp.pm line 240.
Subroutine longmess_heavy redefined at .../Carp.pm line 268.
Subroutine ret_backtrace redefined at .../Carp.pm line 276.
Subroutine ret_summary redefined at .../Carp.pm line 309.
Subroutine short_error_loc redefined at .../Carp.pm line 324.
Subroutine shortmess_heavy redefined at .../Carp.pm line 348.
Subroutine str_len_trim redefined at .../Carp.pm line 361.
Subroutine trusts redefined at .../Carp.pm line 376.
Subroutine trusts_directly redefined at .../Carp.pm line 396.
Constant subroutine CGI::XHTML_DTD redefined at .../constant.pm line 151.
Subroutine _ops_to_nums redefined at .../overloading.pm line 10.
Subroutine import redefined at .../overloading.pm line 19.
Subroutine unimport redefined at .../overloading.pm line 37.

What you said doesn't jive. You must be changing the global %INC instead of a lexical one somewhere.

try with

no warnings 'redefine';

in that subroutine, although, this might have some interesting side effects in the future

I think I found the actual problem and a way to deal with it.

There are two files that I did not create.

file1.pl has some subs. One of these subs does something like this:

sub foo {
  my %INC = (foo => 'bar'); # lexical variable, does not mess with global %INC
  return %INC;
}

file2.pl looks like this:

use vars qw(%INC);     # oops! global variable
require 'file1.pl';

sub bar1 {
  if (!$INC{'foo'}) {
    %INC = &foo();     # this is breaking stuff
  }
  my $hashref = {
    'inc' => \%INC,
  }
  return $hashref;
}

sub bar2 {
  if (!$INC{'foo2'}) {
    %INC = &foo();
  }
}
# and so on

In file3.pl which I created, I have:

use MyModule;
require 'file2.pl';

my $data = &bar1();
my $obj = MyModule->new();
$obj->doStuff();

Now when I call the doStuff() it prints a redefine warning for every item in the global %INC (which is now empty because of file2).

I searched the codebase for %INC and found that only file1 and file2 use it at all. So what I did was change file2 to this:

use vars qw();
require 'file1.pl';

my %INC;     # now lexical, but still the same for all subs in this file
sub bar1 {
  if (!$INC{'foo'}) {
    %INC = &foo();     # this is not breaking stuff any more
  }
  my $hashref = {
    'inc' => \%INC,
  }
  return $hashref;
}

sub bar2 {
  if (!$INC{'foo2'}) {
    %INC = &foo();
  }
}
# and so on
Licencié sous: CC-BY-SA avec attribution
Non affilié à StackOverflow
scroll top