2012-02-15

Perl の use

以前の記事「Pythonのimport」に続き Perl の use について調べてみた。

use はファイルを実行する

Perl における

use Module;

は厳密に以下と同等である。

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

BEGIN ブロックはファイルの実行に当たって最初に(書いてある順に)実行され、その後は二度と実行されない。if の中に書いてあっても必ず実行される。

require Module は Module に .pm を付加したファイル名のファイルを探してそのファイルを実行する。すでに実行済みの場合は実行しない。

ファイルはディレクトリの配列 @INC から探される。

Module をファイル名に変換する際に、:: は / に変換される。これによって、モジュールファイルを階層化ディレクトリに格納することが可能となる。

Module->import() については後述する。

パッケージ

use の動作は以上のような簡単なもので、これだけでは「モジュールをインポート」する事に使えそうに無い。実際、Module.py に sub f が定義してあるだけのとき、use Module したソースファイルからは f() としてしか参照できず、現在の名前空間を汚さずにファイルを読み込むというインポートの役目を果たさない。

use を実用的に使うためには Perl のパッケージを使う必要がある。パッケージは my によって宣言された変数(レキシカル変数)以外の名前が属する名前空間である。名前を定義する(sub によるサブルーチン定義を含む)と「現在の」名前空間(カレントパッケージ)に登録される。カレントパッケージは package Package によって切り替えることができる。カレントパッケージに属さない名前は Package::Name という形式で参照できる。デフォルトの名前空間には main:: により明示的にアクセスできる。

sub f { "main::f()"; }
f();            # => "main::f()"
{
    package Package;
    sub f { "Package::f()"; }
    f();        # => "Package::f()"
    main::f();  # => "main::f()"
}
f();            # => "main::f()"
Package::f();   #=> "Package::f()"

Perl では、use Module されるファイルの先頭に明示的に package Module を書くことで、モジュールのインポートを実現している。

Module.py が

package Module;
sub f() { ... }

のとき、use Module したソースファイルから Module::f() で呼び出すことができる。

my による変数以外は全てカレントパッケージに登録されるので、そのパッケージの外側からも全てのエントリにアクセスできる。つまり情報隠蔽はなされない。

クラスとしてのパッケージ

Perl にはオブジェクト指向をサポートするしくみとしてクラスという概念が用意されている。クラスに対しては ->(矢印演算子)によるメソッド呼び出しが可能である。Perl においてはクラスは単にパッケージのことで、Class->method() によりパッケージ Class のサブルーチン method()、すなわち Class::method() が呼び出される。ただし、このとき -> の左側の値(この場合には Class)が第 1 引数として呼び出される。

(一方「オブジェクト」も単なる Perl の値を bless() したものである。bless() された値はカレントパッケージと結びつけられ、矢印演算子によるメソッド呼び出しは、結びつけられたパッケージのサブルーチン呼び出しになる。これが Perl のオブジェクト指向サポートである。)

import による定義のコピー

use Module は require Module の後、Module->import() というメソッド呼び出しを行う。

必要なら、Module::import() (普通は Module.py の sub import)に定義のコピーを実装できる。つまり、Perl では定義のコピーを示唆する import という名前を使用しているものの、その用途は自由で、実際に定義のコピーを行う際も自分で明示的にする必要があるのだ。

use Module LIST という形式を用いて import 時の細かい指定を実現できる。この形式では Module->import(LIST) という呼び出しが行われる。

定義のコピーは型グロブなど Perl 言語の深い部分を使う必要があるので、あらかじめ用意された Exporter モジュールを用いて行うのが普通である。

シンボルテーブル

Perl のパッケージの実態はハッシュ様のオブジェクトで、名前をキーとして値が引ける表となっている。このハッシュ様オブジェクトには実際に言語からアクセスすることができ、%Module:: というハッシュとして見えるようになっている。このハッシュを操作することで定義のコピーなどを行うことができる。

階層化されたパッケージ

パッケージ名に :: を用いることで、モジュールファイルを階層化ディレクトリに配置できるが、Perl 言語としてはモジュールが階層化されているわけではない。例えば Red::Blue というパッケージは Red というパッケージとも Blue というパッケージとも関係が無い。

(ただし Perl の実装は Red という名前空間が Blue という名前を保持し、その値が Blue 名前空間を持つようになっている。だが言語仕様としてはこの事実は利用されない。)

References

man perlfunc に use, require, import の説明がある。

man perlmod にパッケージ、シンボルテーブルの説明がある。

man perlobj にクラス、メソッド呼び出しの説明がある。

プログラミング Perl」の 10 章にパッケージ、シンボルテーブルの説明がある。

マスタリング Perl」の 10 章にパッケージ、シンボルテーブルの説明がある。

0 件のコメント:

コメントを投稿