2

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.

simbabque
  • 53,749
  • 8
  • 73
  • 136
  • 3
    I'm going to have a fun chat with the guy who built this... – simbabque Jun 29 '12 at 14:22
  • local %INC; would have made more sense. I guess you can't change it now without causing unintended consequences, right? – d5e5 Jun 29 '12 at 14:35
  • @mkb: no, I mean `%INC`. – simbabque Jun 29 '12 at 14:41
  • And it is not used to tell Perl something in the way `%INC` is meant to be used. There is just a variable that has the same name because the guy who built it didn't know about `%INC` being a reserved name. It just has some data in it that the sub needs. – simbabque Jun 29 '12 at 14:43
  • 1
    Cause global search and replace on a file is so difficult? – starbolin Jun 29 '12 at 15:00
  • Yes, you can create it. So what? It have exactly zero special meaning. – Oleg V. Volkov Jun 29 '12 at 15:24
  • Thank you all for your input. I posted what I did to get rid of it. I'm going to accept @eugeney's answer since he answered the question in the topic most accurately. – simbabque Jun 29 '12 at 17:00

6 Answers6

4

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.

Eugene Yarmash
  • 142,882
  • 41
  • 325
  • 378
2

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.

Oleg V. Volkov
  • 21,719
  • 4
  • 44
  • 68
  • 1
    Thank you for the explanation. I just figured that out also. The problem is that in the next script there is a `use vars '%INC'` and several `sub`s that share the `%INC` returned by the sub that has `my %INC`. I'm trying to get rid of that now. – simbabque Jun 29 '12 at 15:33
1

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;
Zaid
  • 36,680
  • 16
  • 86
  • 155
  • That is correct. But in my case the `use vars`/`our %INC` was not in a `package`, but in `main::`. I've adjusted your code and now it shows the warnings. Before the `our %INC` it has the normal values. After it, it there is the `abc => 123` as well as a couple of proper values like `Exporter.pm`, `List/Util.pm` and `vars.pm`. I think with `our` it just deleted the ones defined in `main::` and left the ones that came from `Test`. Very strange. – simbabque Jun 30 '12 at 07:30
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.

ikegami
  • 367,544
  • 15
  • 269
  • 518
  • Thanks for the simple example. You're right of course. I was (made to do it). In [my own answer](http://stackoverflow.com/a/11265936/1331451) I explain in more detail. – simbabque Jun 30 '12 at 07:08
0

try with

no warnings 'redefine';

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

Tudor Constantin
  • 26,330
  • 7
  • 49
  • 72
0

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
simbabque
  • 53,749
  • 8
  • 73
  • 136