"use Foo.pm" twice from inside different packages...
wazoox
created: 2006-03-02 16:44:52
Dear fellow monks, this time I'm done. This one should be obvious, easy, whatever, anyway I can't get it to work so I have to beg your help !
I reproduced easily what's wrong with a very tiny script and modules, so you can explain it easily because obviously there's some basic stuff I'm missing.. So here it is :< readmore>
First the script, script.pl :
#!/usr/bin/perl

use strict;
use warnings;

use lib '.';

use Bozo;

print go_bozo();
Then there's of course the "Bozo.pm" module :
use strict;
use warnings;

# module Bozo

use Exporter;
my @EXPORT=qw( go_bozo);

sub go_bozo {
	return "BOZO!\n"
}

1;
OK, so THIS work exactly as I'd expect it to work. Now, the stuff that's driving me nuts, let's change the script and add an additional module :
#!/usr/bin/perl

use strict;
use warnings;

use lib '.';

use Foo;

print Foo->Foo();
Then the module Foo.pm (please be patient):
#!/usr/bin/perl

use strict;
use warnings;

package Foo;

use lib '.';
use Bozo;

sub Foo {
	return go_bozo()
}

1;
Fine, it still works! Now is coming whant I don't understand, just changing the script a little:
#!/usr/bin/perl

use strict;
use warnings;

use lib '.';

use Bozo;
use Foo;

print go_bozo();

print Foo->Foo();
And now it doesn't work anymore : Undefined subroutine &Foo::go_bozo called at Foo.pm line 13. I understand what's wrong : i'm useing Bozo.pm twice, and that's certainly evil (well actually I don't se why, but never mind...). But why doesn't it give an error such as importing twice the same module at Foo.pm line 10 then ?
What advice could you please give me to manage the megatons of modules I have lying around (OO perl, here I come!) without getting nuts because I wrote use Bar once more than I should have in package #231?
Re: "use Foo.pm" twice from inside different packages...
xdg
created: 2006-03-02 17:01:18

A couple of things are going on here.

  • You're not defining a package for Bozo

  • You're not using Exporter correctly

The result is that when you first use Bozo, go_bozo gets compiled into the current package and the implicit call to import (normally handled by Exporter) does nothing. The second time, the file isn't actually compiled again, and there's still no import, so the sub doesn't get loaded to the new package space, either.

Here's how I'd write them:

package Bozo;                    # make it a package

use strict;
use warnings;

use base 'Exporter';             # subclassing with "base"
our @EXPORT = qw( go_bozo );     # "our" not "my"

sub go_bozo {
    return "BOZO!\n"
}

1;
package Foo;

use strict;
use warnings;

use Bozo;

sub Foo {
    return go_bozo()
}

1;
#!/usr/bin/perl

use strict;
use warnings;

use lib '.';

use Bozo;
use Foo;

print go_bozo();

print Foo->Foo();

Note that I've shifted the use lib just to the top level and did some minor rearranging. The real change is in Bozo.pm in how Exporter is used.

-xdg

Code written by xdg and posted on PerlMonks is public domain. It is provided as is with no warranties, express or implied, of any kind. Posted code may not have been tested. Use of posted code is at your own risk.

Re^2: "use Foo.pm" twice from inside different packages...
created: 2006-03-03 02:49:36
OK, I actually tried to add a "package" definition too (I didn't mentioned everything that I actually tried :), but it didn't help, actually it even got more confusing because from Foo.pm, even Bozo::go_bozo() wouldn't work then; so the lexical @EXPORT should really be the root of all evil in this case.
Re^3: "use Foo.pm" twice from inside different packages...
xdg
created: 2006-03-03 06:35:55

I know this must be frustrating, but once you do it a couple times, it will seem natural. Let me break it down a bit.

First, a [doc://use] statement really does something like this behind the scenes:

# use Module @LIST is really:

BEGIN { 
  require Module; 
  Module->import( @LIST );
}

The [doc://require] call will load a library file just like [doc://do], but only if it hasn't already been loaded. The call to the import method only happens if it is defined in the Module namespace (or is inherited).

So what if you don't have a package statement (and I'm leaving off strict, warnings and Exporter for space and clarity for the moment):

# Bozo.pm

sub go_bozo { return "BOZO!\n" }

1;

The first time you use Bozo, two things happen. First, Bozo.pm is loaded just like do. That means that go_bozo is compiled into the current package. For example:

# script.pl

package Burble;
use Bozo;

package main;
print Burble::go_bozo();

The second thing that happens it that Perl looks to see if it can call Bozo->import. Since no import is defined in Bozo, the call is skipped.

But the second time you use Bozo, require doesn't load it because it was already loaded, and the import still doesn't exist, so nothing happens.

# script.pl

package Burble;
use Bozo;

package Wibble;
use Bozo;

package main;
print Burble::go_bozo(); # OK
print Wibble::go_gozo(): # ERROR - doesn't exist

Now, add a package statement:

# Bozo.pm
package Bozo;

sub go_bozo { return "BOZO!\n" }

1;

Now, when you use Bozo the first time, go_bozo is compiled into the Bozo namespace rather that whatever namespace was in scope in the script file. (However, you still can't just call go_bozo because it hasn't been exported to the current package.)

# script.pl

package Burble;
use Bozo;

package main;
print Bozo::go_bozo();   # OK
print Burble::go_bozo(); # ERROR - doesn't exist
print go_bozo();         # ERROR - main::go_bozo() doesn't exist either

Once you've got that clear, it's time to understand Exporter. Exporter provides the import function that's been missing. Prior to Perl 5.8, you needed to subclass Exporter like this:

# Bozo.pm
package Bozo;

# subclass Exporter
use Exporter;
@ISA = ( 'Exporter' );

sub go_bozo { return "BOZO!\n" }

1;

That can be done shorthand with [doc://base]:

# Bozo.pm
package Bozo;

# subclass Exporter
use base 'Exporter';

sub go_bozo { return "BOZO!\n" }

1;

However, that still won't export go_bozo to the namespace that called use Bozo because you haven't told Exporter what you want to export.

# script.pl

use Bozo;

print Bozo::go_bozo();   # OK
print go_bozo();         # ERROR - main::go_bozo() still doesn't exist

Exporter requires you to put the functions you want to export into a package variable called @Bozo::EXPORT. (So, yes, the lexical is the root of evil -- but that's because Exporter specifically calls for a package variable.)

# Bozo.pm
package Bozo;

# subclass Exporter
use base 'Exporter';

# define exports
@EXPORT = ( 'go_bozo' );

sub go_bozo { return "BOZO!\n" }

1;

Now, when you use Bozo the first time, Bozo.pm is compiled, putting go_bozo in the Bozo namespace. But now, Bozo->import() is called, and exports go_bozo to the caller's namespace. The second time use Bozo is seen, the compilation isn't repeated, but the call to Bozo->import() is, which exports go_bozo again to the caller's namespace. So now you can do this:

# script.pl

package Burble;
use Bozo;

package Wibble;
use Bozo;

package main;
use Bozo;

print Bozo::go_bozo();   # OK
print Burble::go_bozo(); # OK
print Wibble::go_bozo(): # OK
print go_bozo();         # OK

Does that make more sense now? Without the package you wind up compiling the function into the file that calls use Bozo but only the first time. That looks like an export, but it's really not. With the package statement you then have to get the Exporter part right.

-xdg

Code written by xdg and posted on PerlMonks is public domain. It is provided as is with no warranties, express or implied, of any kind. Posted code may not have been tested. Use of posted code is at your own risk.

Re^4: "use Foo.pm" twice from inside different packages...
created: 2006-03-03 06:45:56
Dear friend, that IS the wonderful clear and detailed explication I needed. I can't thank you enough for all this, thank you thank you thank you :)
Re: "use Foo.pm" twice from inside different packages...
created: 2006-03-02 17:01:38
There are two major problems:
  1. Bozo.pm never defines a namespace (package Bozo;) so it's defining its function in main::, not Bozo::
  2. Bozo.pm uses a lexical @EXPORT, not a package variable @EXPORT
Compare your code with this:
# Bozo.pm
package Bozo;

use Exporter;
@Bozo::EXPORT = 'go_bozo';

sub go_bozo { return "bozo!" }

1;
# Foo.pm
package Foo;

use Bozo;

sub proxy { return go_bozo() }

1;
# prog.pl
use strict;
use warnings;

use Bozo;
use Foo;

print go_bozo();
print Foo::proxy();  # or Foo->proxy() if you want 'Foo' sent as the first arg...

Jeff [japhy] Pinyan, [id://371157|P.L., P.M., P.O.D, X.S.]: Perl, regex, and perl hacker
How can we ever be the sold short or the cheated, we who for every service have long ago been overpaid? ~~ Meister Eckhart
Re^2: "use Foo.pm" twice from inside different packages...
xdg
created: 2006-03-02 17:14:09

Just a minor note on the difference in our solutions with respect to Exporter: Perl 5.6 and earlier require Exporter to be subclassed, not just imported.

use Exporter;        # Perl >= 5.8
use base 'Exporter'; # Perl <= 5.6

Even my solution isn't backwards-compatible prior to Perl 5.6 because I included our and warnings. For personal use, this may not matter, but module authors who plan to publish should keep it in mind.

-xdg

Code written by xdg and posted on PerlMonks is public domain. It is provided as is with no warranties, express or implied, of any kind. Posted code may not have been tested. Use of posted code is at your own risk.

Re^3: "use Foo.pm" twice from inside different packages...
created: 2006-03-02 17:15:06
D'oh, right, oops. (Editor's note: I said those words out loud as I typed them.)

Jeff japhy Pinyan, P.L., P.M., P.O.D, X.S.: Perl, regex, and perl hacker
How can we ever be the sold short or the cheated, we who for every service have long ago been overpaid? ~~ Meister Eckhart
Re^3: "use Foo.pm" twice from inside different packages...
created: 2006-03-02 18:12:10
uh, our and use warnings work great in 5.6. I missed "prior to"
Re^3: "use Foo.pm" twice from inside different packages...
created: 2006-03-03 07:04:36
Is there any reason to prefer "use Exporter" instead of the backward-compatible "use base 'Exporter'" when running perl 5.8 anyway ?
Re^4: "use Foo.pm" twice from inside different packages...
xdg
created: 2006-03-03 07:13:51

I don't think there's much of a practical difference. It's shorter and it doesn't add anything to the @ISA array, meaning that there's a shorter inheritance tree for method resolution if you're doing a lot of multiple inheritance.

I think the original subclassing approach was just a bad design choice, but now we're stuck with it if we want to be backwards compatible. But since that isn't an issue for some people (e.g. people writing specifically for desireable features of Perl 5.8, like Unicode), they have the option of moving to the better design.

-xdg

Code written by xdg and posted on PerlMonks is public domain. It is provided as is with no warranties, express or implied, of any kind. Posted code may not have been tested. Use of posted code is at your own risk.

Re^5: "use Foo.pm" twice from inside different packages...
created: 2006-03-03 07:44:56
Arg. I just tried with my real code running perl 5.8.8, and it does actually a difference : use base 'Exporter' works, use Exporter doesn't (??!?!?). The module is absolutely trivial :
package DBtools;

use strict;
use warnings;

use DBI;
use Exporter;

our @EXPORT=qw( dbconnect );

#sub definition
sub dbconnect {
    my $config = shift;

    my $dbh = DBI->connect(
        'DBI:'
          . $config->param('dbdriver')
          . ':dbname='
          . $config->param('dbname')
          . ';host='
          . $config->param('dbhost'),
        $config->param('dbuser'),
        $config->param('dbpassword'),
        { PrintError => 0, RaiseError => 1, AutoCommit => 0 }
      );

    return ($dbh);
}

1;
I'm going to stick with "use base" for now :/
Re^6: "use Foo.pm" twice from inside different packages...
xdg
created: 2006-03-03 08:31:01

My bad. As per the Exporter docs, you need to request import explicitly. (You can see how rarely I actually do that!)

package Blarg;

use Exporter qw( import );

I updated my earlier post.

-xdg

Code written by xdg and posted on PerlMonks is [http://creativecommons.org/licenses/publicdomain|public domain]. It is provided as is with no warranties, express or implied, of any kind. Posted code may not have been tested. Use of posted code is at your own risk.

Re^7: "use Foo.pm" twice from inside different packages...
created: 2006-03-03 09:39:58
Thank you :)
Re^2: "use Foo.pm" twice from inside different packages...
created: 2006-03-03 02:53:36
As I said in my reply to xdg, the package definition actually may be optional, but obviously that's the wrong @EXPORT scoping that killed me :) Shame...
Re^3: "use Foo.pm" twice from inside different packages...
created: 2006-03-03 03:35:40
It isn't optional. If you don't have package Foo; Foo is not a module. See Simple Module Tutorial.
Re^4: "use Foo.pm" twice from inside different packages...
created: 2006-03-03 06:40:06
Yes you're right... Well I'm getting confused with the good' ol' perl4 "require" too :)

perlmonks.org content © perlmonks.org and Anonymous Monk, ikegami, japhy, wazoox, xdg

prlmnks.org © 2006 edmund von der burg (eccles & toad)

v 0.03