Cookie Notice

As far as I know, and as far as I remember, nothing in this page does anything with Cookies.

2013/09/03

Bug in Perl? Or am I just doing it wrong?

Three modules: MyTools::Foo, MyTools::Bar and MyTools::Blee. Foo primarily exports foo(), which returns "foo". Bar, similarly, exports bar() which returns "bar". Same with Blee.

Foo also exports foo_bar(), which concatenates the output of foo() and bar(), and foo_blee(), which does the same with foo() and blee(). Bar has bar_foo() and bar_blee(), and Blee has blee_foo() and blee_bar().

Here, the library holding MyTools is identified using the PERL5LIB environment variable. I do this to model a problem shared by a suite of modules that have spaghetti-like tendencies to interconnect with each other. Previously, I had used use lib '/path/to/lib' to do this purpose, but the need to start using git and the like has pushed me toward using a means to identifying library paths without hardcoding them.

I haven't developed the test case such that, using use lib, it works, but my production uses lib all over the place, and I only noticed the problem when I copied it to a dev directory and pulled those lines.

package MyTools::Bar ;
use strict ;
use warnings ;
use Exporter qw(import) ;
use MyTools::Foo ;
use MyTools::Blee ;
our @EXPORT ;
our @EXPORT_OK ;
our %EXPORT_TAGS ;
BEGIN {
@EXPORT = qw(
bar
bar_foo
bar_blee
) ;
%EXPORT_TAGS = ( 'all' => [ @EXPORT ], ) ;
@EXPORT_OK = ( @{ $EXPORT_TAGS{ 'all' } } ) ;
}
sub bar {
my $bar = 'bar' ;
return $bar ;
}
sub bar_foo {
my $bar = 'bar' ;
my $foo = foo() ;
return join '-' , $bar , $foo ;
}
sub bar_blee {
my $bar = 'bar' ;
my $blee = blee() ;
return join '-' , $bar , $blee ;
}
1
view raw Bar.pm hosted with ❤ by GitHub
package MyTools::Blee ;
use strict ;
use warnings ;
use Exporter qw(import) ;
#use lib '/home/djacoby/dev/MyLibTest/lib' ;
use MyTools::Foo ;
use MyTools::Bar ;
our @EXPORT ;
our @EXPORT_OK ;
our %EXPORT_TAGS ;
BEGIN {
@EXPORT = qw(
blee
blee_foo
blee_bar
) ;
%EXPORT_TAGS = ( 'all' => [ @EXPORT ], ) ;
@EXPORT_OK = ( @{ $EXPORT_TAGS{ 'all' } } ) ;
}
sub blee {
my $blee = 'blee' ;
return $blee ;
}
sub blee_foo {
my $blee = 'blee' ;
my $foo = foo() ;
return join '-' , $blee , $foo ;
}
sub blee_bar {
my $blee = 'blee' ;
my $bar = bar() ;
return join '-' , $blee , $bar ;
}
1
view raw Blee.pm hosted with ❤ by GitHub
package MyTools::Foo ;
use strict ;
use warnings ;
use Exporter qw(import) ;
use MyTools::Bar ;
use MyTools::Blee ;
our @EXPORT ;
our @EXPORT_OK ;
our %EXPORT_TAGS ;
BEGIN {
@EXPORT = qw(
foo
foo_bar
foo_blee
) ;
%EXPORT_TAGS = ( 'all' => [ @EXPORT ], ) ;
@EXPORT_OK = ( @{ $EXPORT_TAGS{ 'all' } } ) ;
}
sub foo {
my $foo = 'foo' ;
return $foo ;
}
sub foo_bar {
my $foo = 'foo' ;
my $bar = bar() ;
return join '-' , $foo , $bar ;
}
sub foo_blee {
my $foo = 'foo' ;
my $blee = blee() ;
return join '-' , $foo , $blee ;
}
1
view raw Foo.pm hosted with ❤ by GitHub
1..9
ok 1 - use MyTools::Foo;
ok 2 - use MyTools::Bar;
ok 3 - use MyTools::Blee;
ok 4 - foo eq foo
ok 5 - bar eq bar
ok 6 - blee eq blee
ok 7 - foo-bar eq foo-bar
ok 8 - bar-blee eq bar-blee
Undefined subroutine &MyTools::Blee::foo called at /home/djacoby/dev/MyLibTest/lib/MyTools/Blee.pm line 32.
# Looks like you planned 9 tests but ran 8.
# Looks like your test exited with 255 just after 8.
djacoby@coates-fe00 17:36:23 ~/dev/MyLibTest $
view raw my results hosted with ❤ by GitHub
#!/bin/env perl
use feature qw{ say } ;
use strict ;
use warnings ;
use Test::More tests => 9 ;
BEGIN { use_ok( 'MyTools::Foo' ); }
BEGIN { use_ok( 'MyTools::Bar' ); }
BEGIN { use_ok( 'MyTools::Blee' ); }
my $foo = foo() ;
ok( 'foo' eq $foo , 'foo eq foo' ) ;
my $bar = bar() ;
ok( 'bar' eq $bar , 'bar eq bar' ) ;
my $blee = blee() ;
ok( 'blee' eq $blee , 'blee eq blee' ) ;
my $foobar = foo_bar() ;
ok( 'foo-bar' eq $foobar , 'foo-bar eq foo-bar' ) ;
my $barblee = bar_blee() ;
ok( 'bar-blee' eq $barblee , 'bar-blee eq bar-blee' ) ;
my $bleefoo = blee_foo() ;
ok( 'blee-foo' eq $bleefoo , 'blee-foo eq blee-foo' ) ;
view raw test.t hosted with ❤ by GitHub
The problem I'm seeing is that Perl starts to look for foo() in Bar or Blee, when foo() is in Foo. Clearly, It'd be better if Foo didn't include Bar and Blee while Bar included Foo and Blee, etc. It would be nice if I had separated the code better in the first place, but seeing that the code base where I started finding this problem is 19 modules with over 8,000 lines and is used across several systems by someone else, so every change has the potential to break my lab's workflow, I can't really disentangle it right now.

So, it strikes me that Perl is wrong, too. (I fully admit that my code is an unruly hairball. I'm starting to pay that technical debt right now.) I'm somewhat loathe to tag this as an error in Perl and start filing bug reports until someone with more direct experience looks at this and says either "That's odd" or "Dave, you're a dumbass." I would certainly accept either answer.

So, am I wrong?