Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

What is @ISA in Perl?

If I have a module with methods a and b and want to export them I do:

use Exporter;  
our @ISA = qw (Exporter);  
our @EXPORT = qw (a b);  

What I don't understand is what does this line:
our @ISA = qw (Exporter); do?

like image 544
Jim Avatar asked Jul 29 '13 18:07

Jim


4 Answers

The @Foo::ISA array is a global variable that holds the classes from which class Foo inherits.

Generally, you shouldn't manipulate @ISA directly; doing so is a sign that you're probably looking at old Perl code.

If you want to declare an inheritance relationship, a better way to do it is

use parent 'Exporter';

which tweaks @ISA behind the scenes for you and also does some other useful stuff.

In your case, when you do

our @ISA = qw(Exporter)

you're declaring your class as a subclass of Exporter. The Exporter class provides a method called import. Why do you want that? Because when you say

use MyClass;

What actually happens is:

BEGIN { 
    require 'MyClass.pm';
    MyClass->import;
};

The import method is automatically called every time someone uses your class. That method can do anything you want. (You could write your own import if you want to) but usually it's used to import symbols into the caller's namespace. That's what Exporter does for you.

However, Exporter also exports its own import method, so you don't actually have to inherit it any more. (This was fixed a loooong time ago.) So now you can just say

use Exporter qw(import);

and your package will get the import method without having to mess with @ISA at all.

like image 142
friedo Avatar answered Sep 27 '22 17:09

friedo


Think object oriented here.

Think of Exporter not as a mere module, but as a class. Think of ISA as meaning "Is a" as in "My module is a sub-class of Exporter".

What you're doing is declaring your module as a sub-class of the Exporter class which means you can use the import method of the Exporter class which is sort of useful.

To really explain what Exporter is doing, you must understand that Perl uses Namespaces. Imagine if your program has a variable1 called $total, but so does the module you're using. Your $total variable would interfere with the module's $total variable.

To prevent this, Perl uses namespaces. Your program operates in the default namespace of main. Your modules use the package function to declare a new namespace. Now, both you and your module can safely use a variable called $total. In your program, it's really $main::total, and in the package, it's $Package::Name::total. If you want to use something from one _namespace_ in another, you can prepend the _namespace_ on it. Think of the$File::Find::nameand$File::Find::dirvariables you have when you useFile::Find`.

What the Exporter's import method does is copy your subroutines (and if you so desire, your variables) from your namespace to the current namespace. Imagine using the File::Copy module without the ability to copy over the copy subroutine to your main namespace. You could still use it, but you'd have to give it the name of the namespace on it:

use File::Copy;

...

File::Copy::copy( $from_file, $to_file );

Thanks to Exporter (and the import method), any subroutines you put into your packages @EXPORT array are copied over to the current namespace. Thus, you can access File::Copyscopy` subroutine like this:

use File::Copy;

...

copy ( $from_file, $to_file );

This is also why you must declare all of these variables as our and not my. my variables are lexically scoped and cannot be accessed outside of where they're declared. Package variables (like $File::Find::name) can be. For Exporter to find your @EXPORT, and @EXPORT_OK arrays, these need to be package variables.

Now, comes the desirability of exporting functions...

The oldest modules that we know and love export subroutines willy-nilly. You use File::Copy, File::Path, File::Find, and you have immediate access to their subroutines. This is because they put their subroutines into the @EXPORT array. This was at one time thought desirable because it makes these functions immediately available to you.

Newer modules like File::Temp require you to declare the subroutines you want to import:

use File::Temp qw(tempdir);

...
my $temp_dir = tempdir;

If I didn't have that qw(tempdir), I couldn't use the tempdir function.

This is considered polite. The module is asking your permission to import the function. This is done by putting the subroutines into @EXPORT_OK. These will only be exported upon request.

This is better because you don't have to import everything, just what you need. And, you're documenting where these functions are defined.

Object Oriented modules don't export anything at all and don't need to use Exporter. It's been a long time since I've written a module that uses Exporter.

-- 1 We're talking about package variables here. Package variables are visible everywhere.

like image 24
David W. Avatar answered Sep 27 '22 19:09

David W.


The @ISA package variable is used to specify inheritance between classes. You are discouraged to manipulate this variable yourself. If you want to inherit from another class, do

use parent 'Parent::Class';

or pre v10.1:

use base 'Parent::Class';

In this specific case, inheriting from Exporter makes the import method available. Your code could be rewritten as.

use parent 'Exporter';
our @EXPORT = qw/a b/;

The import method is called automatically when your module is used, and may export symbols to the using package.


Why using @ISA manually is bad:

  • Do not assign to @ISA: Other modules may have already added entries to it; this would overwrite them. Therefore, push @ISA, "Some::Class".

  • Avoid modifying @ISA during runtime. It is better to specify the inheritance relationship as early as possible (during parsing or after initial compilation), so that your module could be used there without restrictions. You could wrap it in an BEGIN or CHECK block, like

    BEGIN {
      push @ISA, "Some::Class";
    }
    

Inheritance via parent makes this much easier. parent will also compile the requested module if it isn't already loaded: no need for use Some::Class.

like image 20
amon Avatar answered Sep 27 '22 18:09

amon


It instructs Perl to look in the Exporter module for methods when it can't find them in your package. The usual method you want to inherit from Exporter is its import method, which is where the work of copying your module's exported symbols to the calling package takes place.

From perlobj:

Each package contains a special array called @ISA. The @ISA array contains a list of that class's parent classes, if any. This array is examined when Perl does method resolution, which we will cover later.

For example, this is an error because Perl will try to call the non-existent subroutine Foo::some_method:

sub Bar::some_method { 42 }
my $obj = bless {}, 'Foo';
$obj->some_method;

The @ISA variable in a package tells Perl to look for the method in other packages, so this code will work and invoke the Bar::some_method method.

sub Bar::some_method { 42 }
my $obj = bless {}, 'Foo';
@Foo::ISA = qw(Bar);
$obj->some_method;

The practical application for this is inheritance.

As amon mentions, there is rarely a need to set @ISA directly. The parent pragma (and the older, now discouraged base pragma) declare inheritance relationships and set this variable for you.

like image 38
mob Avatar answered Sep 27 '22 19:09

mob