tags:

views:

182

answers:

5

It seems strange to me that Perl would allow a package to export symbols into another package's namespace. The exporting package doesn't know if the using package already defined a symbol by the same name, and it certainly can't guarantee that it's the only package exporting a symbol by that name.

A very common problem caused by this is using CGI and LWP::Simple at the same time. Both packages export head() and cause an error. I know, it's easy enough to work around, but that's not the point. You shouldn't have to employ work arounds to use two practically-core Perl libraries.

As far as I can see, the only reason to do this is laziness. You save some key strokes by not typing Foo:: or using an object interface, but is it really worth it?

+9  A: 

The practice of exporting all the functions from a module by default is not the recommended one for Perl. You should only export functions if you have a good reason. The recommended practice is to use EXPORT_OK so that the user has to type the name of the required function, like:

use My::Module 'my_function';

Modules from way back when, like LWP::Simple and CGI, were written before this recommendation came in, and it's hard now to alter them to not export things since it would break existing software. I guess the recommendation came about through people noticing problems like that.

Anyway Perl's object-oriented objects or whatever it's called doesn't require you to export anything, and you don't not have to say $foo->, so that part of your question is wrong.

Kinopiko
He's saying that it saves space. But yes, the `$foo->` bit is technically incorrect, and doesn't really refer to namespaces.
Chris Lutz
$foo-> as in:my $foo = new Blah::Whatever;$foo->bar();
Ryan Fox
Exporter says "Do not export anything else by default without a good reason!" People seem to ignore the "without a good reason" part. If you have a module that operates by the user calling a handful of functions go ahead and export them by default! Make the default the common case. Don't let monsters like CGI make you never export anything.
Schwern
I've altered it slightly. Are you happy with that?
Kinopiko
I think it derives from Perl's origins in Unix scripting. There it is the rule for software packages to export their commands (executables) into your $PATH. Perl 4.036 was still basically an enormous grab bag of built-in functions, replacing not only standard Unix utilities but also C library calls and Unix system calls. No namespacing. There was a namespacing mechanism(packages) but it was weak and unpopular. Perl 5 and CPAN changed all that, but only gradually. CGI was among the first truly OO pieces of Perl code so it stands to reason that it offered a more traditional interface as well.
reinierpost
+6  A: 

The exporting package doesn't know if the using package already defined a symbol by the same name, and it certainly can't guarantee that it's the only package exporting a symbol by that name.

If you wanted to, I imagine your import() routine could check, but the default Exporter.pm routine doesn't check (and probably shouldn't, because it's going to get used a lot, and always checking if a name is defined will cause a major slowdown (and if you found a conflict, what is Exporter expected to do?)).

As far as I can see, the only reason to do this is laziness. You save some key strokes by not typing Foo:: or using an object interface, but is it really worth it?

Foo:: isn't so bad, but consider My::Company::Private::Special::Namespace:: - your code will look much cleaner if we just export a few things. Not everything can (or should) be in a top-level namespace.

The exporting mechanism should be used when it makes code cleaner. When namespaces collide, it shouldn't be used, because it obviously isn't making code cleaner, but otherwise I'm a fan of exporting things when requested.

Chris Lutz
The aliased module is a fine solution to overly long namespaces.
brian d foy
It is a good general solution, but since we should know what kinds of things will be exported from `My::Company::Private::Special::Namespace::` we should be able to make an accurate judgment of whether it will clash with anything we already have/are exporting. And if there's no clash, why not go ahead and export it?
Chris Lutz
+3  A: 

It's not just laziness, and it's not just old modules. Take Moose, "the post-modern object system", and Rose::DB::Object, the object interface to a popular ORM. Both import the meta method into the useing package's symbol table in order to provide features in that module.

It's not really any different than the problem of multiply inheriting from modules that each provide a method of the same name, except that the order of your parentage would decide which version of that method would get called (or you could define your own overridden version that somehow manually folded the features of both parents together).

Personally I'd love to be able to combine Rose::DB::Object with Moose, but it's not that big a deal to work around: one can make a Moose-derived class that “has a” Rose::DB::Object-derived object within it, rather than one that “is a” (i.e., inherits from) Rose::DB::Object.

Ether
However, Moose also unimports its mess with 'no Moose'. It's not being sloppy at all.
brian d foy
@brian: Indeed! And 'no Moose' does some other optimization that's quite nice to have.
Ether
+9  A: 

Exporting is a feature. Like every other feature in any language, it can cause problems if you (ab)use it too frequently, or where you shouldn't. It's good when used wisely and bad otherwise, just like any other feature.

Back in the day when there weren't many modules around, it didn't seem like such a bad thing to export things by default. With 15,000 packages on CPAN, however, there are bound to be conflicts and that's unfortunate. However, fixing the modules now might break existing code. Whenever you make a poor interface choice and release it to the public, you're committed to it even if you don't like it.

So, it sucks, but that's the way it is, and there are ways around it.

brian d foy
+3  A: 

One of the beautiful things about Perl's "open" packages is that if you aren't crazy about the way a module author designed something, you can change it.

package LWPS;
require LWP::Simple;

for my $sub (@LWP::Simple::EXPORT, @LWP::Simple::EXPORT_OK) {
    no strict 'refs';
    *$sub = sub {shift; goto &{'LWP::Simple::' . $sub}};
}

package main;

my $page = LWPS->get('http://...');

of course in this case, LWP::Simple::get() would probably be better.

Eric Strom