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

At the risk of sounding like The Boy Who Cried Wolf, I really do wonder if I have discovered a bug in Array::Compare.

When running the following code:

#!/usr/bin/perl -w use strict; use warnings; use Array::Compare; my $comp1 = Array::Compare->new; $comp1->Sep ('|'); $comp1->Skip ({3 => 1, 4 => 1}); $comp1->WhiteSpace (0); $comp1->Case (1); my $comp2 = Array::Compare->new ( Sep => '|', WhiteSpace => 0, Case => 1, Skip => {3 => 1, 4 => 1} ); my @arr1 = 0 .. 10; my @arr2 = 0 .. 10; if ($comp1->simple_compare (\@arr1, \@arr2)) { print "Arrays are the same\n"; } else { print "Arrays are different\n"; } if ($comp2->simple_compare (\@arr1, \@arr2)) { print "Arrays are the same\n"; } else { print "Arrays are different\n"; }

Under both 5.8 and 5.10 (thanks, CountZero!), I get the following warnings:

Use of uninitialized value $caller in string eq at /usr/lib/perl5/site +_perl/5.8/Array/Compare.pm line 328. Arrays are the same Use of uninitialized value $caller in string eq at /usr/lib/perl5/site +_perl/5.8/Array/Compare.pm line 328. Arrays are the same

When I run my program under the debugger, I note that the line preceeding (327) reads:

my ($pkg, $caller) = (caller(1))[0, 3];

and that after 327 is executed, $caller is undef.

Now, when you x (caller(1))[0, 3] within the debugger, obviously you get something a wee bit different than the program is seeing:

('DB', 'DB::eval')

However, x (caller(3))[0, 3] seems to return what I believe Array::Compare is expecting:

('main','Array::Compare::simple_compare')

It looks to me like something very weird is going on. Why isn't $caller set to Array::Compare::simple_compare? Why is $caller undef, therefore causing the "uninitialized value in string eq" as shown above?

Any insights will be greatly appreciated. Thanks in advance!

planetscape

Replies are listed 'Best First'.
Re: Bug in Array::Compare? (no, really)
by ysth (Canon) on Apr 19, 2009 at 08:54 UTC
    caller(1) is attempting to get information about the subroutine that called simple_compare (in particular, to see if it is Array::Compare::perm). Since you are calling it from your main program, there is no such subroutine, and caller(1) returns an empty list.

    When you call caller from the debugger command line, the debugger's own stack of calls gets in the way and produces different results.

Re: Bug in Array::Compare? (no, really)
by CountZero (Bishop) on Apr 19, 2009 at 10:04 UTC
    If you change
    my ($pkg, $caller) = (caller(1))[0, 3]; my $perm = $caller eq __PACKAGE__ . "::perm";
    to
    my ($pkg, $caller) = (caller(1))[0, 3]; $caller = '' unless $caller; my $perm = $caller eq __PACKAGE__ . "::perm";
    your problem is solved.

    CountZero

    A program should be light and agile, its subroutines connected like a string of pearls. The spirit and intent of the program should be retained throughout. There should be neither too little or too much, neither needless loops nor useless variables, neither lack of structure nor overwhelming rigidity." - The Tao of Programming, 4.1 - Geoffrey James

      or $caller //= ''; in 5.10! (or just complain to the maintainer)
        or $caller //= ''; in 5.10!
        That is really a terrible idea! It would turn the warning (which is only mildly annoying) to a real error in all pre-5.10 systems and thus break all programs using it.

        CountZero

        A program should be light and agile, its subroutines connected like a string of pearls. The spirit and intent of the program should be retained throughout. There should be neither too little or too much, neither needless loops nor useless variables, neither lack of structure nor overwhelming rigidity." - The Tao of Programming, 4.1 - Geoffrey James

Re: Bug in Array::Compare? (no, really)
by bart (Canon) on Apr 19, 2009 at 17:52 UTC
    You mean the behavior of Array::Compare depends on the behavior of caller... to which I can only say: WTF???

    That seems like the worst possible way to implement anything (apart from modules that actually have a reason to depend on caller).

    Well, I've glanced at the source. It is true. I am appalled.

      Yes, it's almost shocking that simple_compare wasn't just given an additional parameter to request the different behavior (or perm and simple_compare both made to call a third, internal function with an extra parameter).
Re: Bug in Array::Compare? (no, really)
by ikegami (Patriarch) on Apr 19, 2009 at 09:37 UTC

    Yes, there's a bug. He's getting the caller's caller's package (caller(1)) instead of checking the caller's package (caller() or caller(0)).

    It's a common mistake. The documentation is a misleading. One has to realize $package, $filename and $line are the caller's $package, $filename and $line, even when caller is provided an argument.

    Update: Doh, he's not working with $package, $filename or $line. Warnings were forced onto a module that wasn't written to work with them and/or he didn't account for simple_compare being called from the top level.