What is special about the perl import subroutine?

Viewed 953

It took me two hours to track down this error. I can work around it, but I don't understand it.

If I have a perl module ./lib/My/Foo.pm that looks like this:

package My::Foo;

sub import {print "importing\n"}

1;

Then using it calls the import subroutine implicitly:

$ PERL5LIB=./lib perl -MMy::Foo -e 'print "ok\n"'
importing
ok

But if I copy the same module and use it without the colons, the import subroutine is not called.

$ cp lib/My/Foo.pm lib/Foo.pm
$ PERL5LIB=./lib perl -MFoo -e 'print "ok\n"'
ok

If I change import to something else like do_import, the subroutine isn't called. So I can avoid this behavior. But in my real use case, I have an Import class and with an abstract method import, then implement that method in subclasses. So I don't want this import method called automatically when useing the parent class.

I looked in perlootut and perlobj and didn't see any mention of this.

4 Answers

import() is a special method name in Perl. Whenever you use a module, Perl will look for a subroutine called import() inside that module and, if it finds it, it will be run.

This is most often used for Exporter cleverness. It means that having a method called import() in your module that you don't want to be called as the module is loaded is a very bad idea. It will leave you fighting against Perl at every turn.

See perldoc -f import for pointers to more information:

import LIST

There is no builtin import function. It is just an ordinary method (subroutine) defined (or inherited) by modules that wish to export names to another module. The use function calls the import method for the package used. See also use, perlmod, and Exporter.

The "workaround" you have found is also not a very good idea. You are effectively loading a module called My:Foo from a file called Foo.pm and Perl will get very confused if the filename and package name don't match.

Seems to me that you're looking at the wrong end of this camel. Your problem isn't caused by import being "special", but rather by not knowing what exactly use actually does. Per perldoc use, use Module is "exactly equivalent" to

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

When you use use, you are telling Perl to call the Module's import method. Simple as that.

Of course, Perl being Perl, there probably is some way for your import method to figure out whether it's being called as part of a use and immediately return if that's the case, but that would just add needless complexity. Renaming the method to something more descriptive (e.g., import_file, import_record, etc., depending on what it is that you're actually importing) would be a much better solution.

import is special in two ways:

Unless use is explicitly given an empty import list (e.g. use Foo ();), import will be called at compile time as a class method and passed any import list arguments use was given.

If import is called as a instance or class method (whether implicitly by use or explicitly) and no such method exists, an empty list will be returned instead of a Can't locate object method error being thrown or AUTOLOAD being called.

If it were implemented today, it would probably be called IMPORT instead.

All of the above also applies to unimport (but with no instead of use).

Update: some have linked to the docs where it says what use is "exactly equivalent" to and then lies.

It is exactly equivalent to BEGIN { require Module; Module::->VERSION(...); Module::->import(...) } except the VERSION call is omitted if no version is specified and the import call is omitted if an explict empty list is given (as the docs later clarify).

(Also note the subtle distinction between Module->import (which calls a Module() function if it exists and then calls the import method on whatever that returns) and Module::->import or 'Module'->import which is a straightforward class method call on the Module class.)

import is a reserved keyword. When you use a module, its import method will be called, see the documentation.

I'm afraid you can't change that. Rename your method to something else that isn't a special keyword.

Related