What is @ISA in Perl?

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

 use Exporter; our @ISA = qw (Exporter); our @EXPORT = qw (ab); 

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

+6
source share
4 answers

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

As a general rule, you should not directly manipulate @ISA ; this means that you are probably looking at old Perl code.

If you want to declare an inheritance relationship, the best way to do this is to

 use parent 'Exporter'; 

which fakes @ISA behind the scenes for you and also does some other useful things.

In your case, when you do

 our @ISA = qw(Exporter) 

you declare your class a subclass of Exporter . The Exporter class provides a method called import . Why do you need this? Because when you say

 use MyClass; 

What is actually going on:

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

The import method is automatically called every time someone use your class. This method can do whatever you want. (You can write your own import if you want), but it is usually used to import characters into the caller's namespace. This is what Exporter does for you.

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

 use Exporter qw(import); 

and your package will get the import method without contacting @ISA at all.

+11
source

Think that the object is oriented here.

Think of the exporter not as a module, but as a class. Think of ISA as the meaning of "is", as in "My module is a subclass of the exporter class ."

What you do declares your module as a subclass of the Exporter class, which means that you can use the import method of the Exporter class, which is useful.

In order to really explain what Exporter does, you must understand that Perl uses a namespace. Imagine that your program has a variable 1 called $total , but also the module you are using. Your $total variable will interfere with the $total module variable.

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

What the Exporter import method does is copy your routines (and if you wish, your variables) from your namespace to the current namespace. Imagine that you are using the File::Copy module without the ability to copy the copy routine to the main namespace. You can use it anyway, but you need to specify the namespace name on it:

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

Thanks to Exporter (and the import method), any routines that you put in your @EXPORT package @EXPORT are copied to the current namespace. Thus, you can access the File :: Copy s copy` routine as follows:

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

This is why you should declare all of these variables as our , not my . my variables are lexically limited and cannot be accessed outside of where they are declared. Package variables (e.g. $File::Find::name ) may be. For Exporter , to find the @EXPORT and @EXPORT_OK , they must be package variables.

Now it becomes desirable to export functions ...

The oldest modules that we know and love export routines are perforce. You use File :: Copy, File :: Path, File :: Find and have immediate access to their routines. This is because they put their routines in the @EXPORT array. This was once considered desirable because it immediately provided you with these features.

Newer modules, such as File::Temp , require declaring the routines you want to import:

 use File::Temp qw(tempdir); ... my $temp_dir = tempdir; 

If I did not have this qw(tempdir) , I could not use the tempdir function.

This is considered polite. The module asks for your permission to import this feature. This is done by putting the routines in @EXPORT_OK . They will be exported only upon request.

This is better because you do not need to import everything, just what you need. And you document where these functions are defined.

Object-oriented modules do not export anything and do not require the use of Export. This has been a long time since I wrote a module that uses Exporter.

- 1 Here we are talking about package variables. Package variables are visible everywhere.

+6
source

The @ISA package @ISA used to indicate inheritance between classes. You are not recommended 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 particular case, inheriting from Exporter makes the import method available. Your code can be rewritten as.

 use parent 'Exporter'; our @EXPORT = qw/ab/; 

The import method is called automatically when your module use d, and can export characters to the package you are using.


Why using @ISA manually is bad:

  • Do not assign @ISA : other modules may have entries already added; it will rewrite them. Therefore push @ISA, "Some::Class" .

  • Avoid changing @ISA at runtime. It’s best to specify inheritance relationships as early as possible (during parsing or after the initial compilation) so that your module can be used there without restrictions. You can wrap it in a BEGIN or CHECK block, for example

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

Inheriting through parent makes this a lot easier. parent also compile the requested module if it is not already loaded: there is no need to use Some::Class .

+3
source

It instructs Perl to look for methods in the Exporter module when it cannot find them in your package. The usual method that you want to inherit from Exporter is its import method, in which the operation of copying your module to the exported characters in the calling package occurs.

From perlobj :

Each package contains a special array named @ISA . The @ISA array contains a list of the parent classes of this class, if any. This array is considered when Perl executes method resolution, which we will discuss later.

For example, this is a mistake because Perl will try to call the nonexistent routine Foo::some_method :

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

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

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

A practical application for this is inheritance.

As mentioned above, it is rarely required to install @ISA . The parent pragma (and the older, now discouraged base pragma) declares an inheritance relationship and sets this variable for you.

+3
source

Source: https://habr.com/ru/post/950570/


All Articles