Search code examples
eclipseperlepic

Eclipse: Perl EPIC debug & release mode execution mismatch


I am noticing an execution mismatch of Perl in Eclipse EPIC plugin.

Specifications:

Perl version: (v5.12.4) built for MSWin32-x86-multi-thread

Eclipse version: Indigo Service Release 2

EPIC version: 0.6.53

Consider the files & source codes below: (all source files are in same directory)

sample.pl

use package1;

require "package1.pm";
require "package2.pm";

sampleFunction();

require "packagetest.pm";

packagetest::callSampleFunction();

package1.pm

package package1;

use Exporter;

our @ISA = qw(Exporter);

our @EXPORT = qw(
    sampleFunction
);

sub sampleFunction {
    print "from package1.pm \n";    
}

package2.pm

package package1;  # declare the same package 'package1'

use Exporter;

our @ISA = qw(Exporter);

our @EXPORT = qw(
    sampleFunction
);

sub sampleFunction {
    print "from package2.pm \n";    
}

packagetest.pm

package packagetest;

use package1;

sub callSampleFunction {
    sampleFunction();
}

1;

When I execute the sample.pl file in Eclipse EPIC, I am getting two different console outputs.

Debug mode output:

from package2.pm 
from package2.pm

Run mode output:

Subroutine sampleFunction redefined at D:/My.Soft.Dev/Perl_XS/package2.pm line 11.
from package1.pm 
from package2.pm 

I have the below questions:

1) Why am I getting two different outputs here? Is it not a bug?

2) Which of the outputs shown is a "valid output"?

3) Can someone explain why is the particular output valid?

I tried to derive the reasons from my Perl knowledge. But I couldn't. So, I understood, I have to get to know more about Perl:))

UPDATE: I have created a bug report: https://sourceforge.net/p/e-p-i-c/bugs/669/

Looks like (1) is a bug in Perl debugger of 5.12.4 version


Solution

  • Regarding questions #2 and #3:

    Your release mode output is the valid one:

    • use package1 finds, loads, compiles, and executes package1.pm. This defines package1::sampleFunction, which is exported into the main namespace. Exporting is effectively done by reference, and not by name, so main::sampleFunction points to the same function which package1::sampleFunction currently refers to.

    • require "package1.pm does nothing because that package has already been executed.

    • require "package2.pm finds, loads, compiles and executes package2.pm. This redefines package1::sampleFunction, which will warn if and only if you have warnings activated – either lexically through use warnings (do this) or globally with the -w switch (don't do this).

    • sampleFunction() executes main::SampleFunction, which still points to the original subroutine.

      from package1.pm

    • require "packagetest.pm" finds, loads, compiles and executes packagetest.pm. Here in turn:

      • use package1 will export package1::sampleFunction (which is currently the redefined subroutine) into the packagetest namespace.

      We also define the packagetest::callSampleFunction subroutine.

    • We call packagetest::callSampleFunction, which in turn

      • calls packagetest::sampleFunction, which is the redefined subroutine

        from package2.pm

    A guess regarding #1:

    The output could come together if we executed the script normally but kept the interpreter with its global state alive, then recompile and re-execute sample.pl. In this case, package1.pm and package2.pm would not be re-executed because they are already loaded. The use package1 would then import the current package1::sampleFunction which already is the redefined version.

    To test this hypothesis, restart your IDE and execute the script two times in debug mode. It should then output

    from package1.pm
    from package2.pm
    

    during the first run, and

    from package2.pm
    from package2.pm
    

    for all subsequent runs.


    The real problem is

    1. that you are redefining subroutines (don't do this),

    2. that you are using the same package name package1 in different files (don't do this),

    3. that you are using a filename package2.pm that does not correspond to the package name package1 inside (don't do this either), and

    4. that you have a number of other style issues, including:

      • lowercase package names are reserved for “pragmatic modules”
      • don't export by default, instead use @EXPORT_OK and let the user of your module explicitly request some symbol
      • require "filename" is usually not something you want to do.
      • You did not use strict; use warnings
      • You are using warnings in production, but not in development? Why? :(
      • You are using the -w switch which is a bit oudated.