Unexpected %INC behaviour on recursive use.

osfameron on 2007-06-14T11:57:31

We noticed a lot of "subroutine redefined" warnings in our apache logs. A little investigation later, and it turns out the problem is with recursive uses.

Consider the following modules (named after the classic Italian metasyntactic characters)

 package Pippo;
 use strict; use warnings;
 use Data::Dumper;
 BEGIN { warn Dumper( { Pippo => \%INC } ); }
 use Pluto;
 sub dummy1 { ; }
 1;
and
 package Pluto;
 use strict; use warnings;
 use Data::Dumper;
 BEGIN { warn Dumper( { Pluto => \%INC } ); }
 use Pippo;
 sub dummy2 {;}
 1;

Here's some output for perl -c (trimming the Dumper output to just show these 2 modules)

$ perl -c Pippo.pm
$VAR1 = {
          'Pippo' => { }
        };
$VAR1 = {
          'Pluto' => {
                       'Pluto.pm' => 'Pluto.pm',
                     }
        };
$VAR1 = {
          'Pippo' => {
                       'Pippo.pm' => 'Pippo.pm',
                       'Pluto.pm' => 'Pluto.pm',
                     }
        };
Subroutine dummy1 redefined at Pippo.pm line 8.
Pippo.pm syntax OK

That is, the first module, Pippo, doesn't set its entry in %INC until after it's finished processing. The use'd module sets its entry in %INC immediately, which is handy, as otherwise we'd have an infinite recursive use. As it is, only Pippo gets used twice, triggering the "Subroutine redefined" warning.

I whined about this in #london.pm, and Nicholas suggested that the timing of this behaviour might possibly be considered a bug. Is there a case for saying that %INC should be set for the file first invoked by perl?

Recursive uses are very likely on the "well don't do that" list, but the timing surprises me in any case.


Maybe changing usage works

ferreira on 2007-06-14T12:28:21

When you're saying "perl -c Pippo.pm", you are compiling and running a package without a surrounding require, and then "use Pluto" works alright.

Compare that with the output of "perl -c -e 'use Pippo'". It seems more well behaved (and does not emit warnings).

$ perl -c -e 'use Pippo'
$VAR1 = {
          'Pippo' => {
                       'Pippo.pm' => 'Pippo.pm'
                     }
        };
$VAR1 = {
          'Pluto' => {
                       'Pluto.pm' => 'Pluto.pm',
                       'Pippo.pm' => 'Pippo.pm'
                     }
        };
-e syntax OK
In your example, you compile "Pippo.pm" which uses "Pluto.pm" which uses "Pippo.pm" (which does not take into account that Pippo.pm is being compiled). When "use Pluto" succeeds, the subroutines in Pippo.pm are redefined.

Workarounds

osfameron on 2007-06-14T13:26:16

Actually, that's quite cute, though you don't need the -c anymore (it checks the syntax of the expression "use Pippo"). And it does clarify the difference between running a file and useing it.

But it would be nice to be able to "perl -c" the file directly (as it's burned into my finger memory as well as my Vim configuration).

Oh, I forgot to post the workaround I use:

package Pippo;
BEGIN { $INC{'Pippo.pm'} = $0}