名前空間(2) package

大規模なプログラムを作る時に絶対に必要となる名前空間というものがあります。
プログラムを多人数で作ったり、モジュールに分割したりする時、皆がみんな好き勝手に変数を使って関数を定義していると、どうしても名前が衝突してしまいます。
名前空間」という概念を導入すると、ある名前空間の中で宣言した変数や定義した関数の名前が、別の名前空間の中の変数や関数の名前と衝突しても、ちゃんと別の物として扱ってくれるようになります。
同じ「鈴木さん」でも「1年2組の鈴木さん」と「3年1組の鈴木さん」が区別できるように、頭に「?の」と付けるのと同じことですね。
Perlでは「package」という宣言をすることで、名前空間(パッケージ)を定義する事ができます。

package Palmo;

と書けば、以降のコードは Palmo 名前空間で実行される事になります。package 宣言で開始した名前空間は「レキシカルスコープ」(package宣言を囲むスコープ)の終わりまで、もしくは他のpackage宣言がされるまで有効です。
宣言された変数名や関数名などの識別子は、現在の名前空間に属します。ただし、「my」付きで宣言された変数は名前空間とは関係なく、そのスコープ内でのみ有効です。
今まで our で宣言した変数の事を「グローバル変数」と呼んでいましたが、実際には Perl にはグローバル変数は存在せず、どんな変数でも必ずいずれかの名前空間に所属しています(パッケージ変数)。

package Human;
our $animal = 'human';

の $animal と

package Lion;
our $animal = 'lion';

の $animal は全くの別物になります。
プログラムの開始直後は「main」名前空間が用いられるので、今までに僕が書いてきたスクリプトは、どれも main 名前空間の中で動いていた事になります。ちなみに、$_ や $! などの特別な変数は main 空間に属します。
パッケージ名に「::」(コロン2つ)を使う事で階層を表現できます。例えば

package School::Grade1::Class2;

と書けば「学校の中の1年の中の2組」という意味のパッケージを定義できます。
ただし、階層表現は人間だけに向けたもので、Perlにとっては「School::Grade1」と「School::Grade1::Class2」は全く関係ないものになります。
特定のパッケージの識別子を表現するには、識別子の前に「パッケージ名::」と書きます。例えば「$School::Grade1::Class2::suzuki」と書けば「School::Grade1::Class2」パッケージに所属する「$suzuki」という変数を表します。また、パッケージ名を省略して「$::hoge」のように書くと「$main::hoge」と同じ意味になります。
このように識別子のパッケージを特定する事を「修飾する」(qualify)と言います。
階層表現はPCでのファイルシステムに似ていますね。フォルダがパッケージ、ファイルが識別子みたいです。(^_^)
パッケージの動作を確かめてみます。まず、ファイルを3つ作ります。

# human.pl
package Human;
our $animal = 'human';
# lion.pl
package Lion;
our $animal = 'lion';
# tiger.pl
package Tiger;
our $animal = 'tiger';

our でそれぞれ $animal というパッケージ変数を宣言しています。ただし、package で名前空間を変更しているので、これらの変数は別のものであるはずです。

# packtest.pl
require 'human.pl';
require 'lion.pl';
require 'tiger.pl';
 
package Human;
print "package Human : $animal\n";
package Lion;
print "package Lion  : $animal\n";
package Tiger;
print "package Tiger : $animal\n";

がメインとなるファイルです。「require」を使うと他のPerlスクリプトファイルを読み込む事ができます。(requireについては後で詳しく調べます) C言語の #include のようなものでしょうか。
その後、それぞれの名前空間で $animal の中身を表示しています。
以下が実行結果です。

package Human : human
package Lion  : lion
package Tiger : tiger

ちゃんと違う値が表示されました。(^_^)
最初は1つのファイルでやろうと思ったのですが、修飾せずに $animal とだけ書くと、パッケージ変数よりもより近くで宣言された同名の変数が優先されてしまうので、ファイルを分割しました。
上の例は以下とほぼ同じ意味ですね。

# packtest2.pl
 
package Human;
our $animal = 'human';
package Lion;
our $animal = 'lion';
package Tiger;
our $animal = 'tiger';
 
package main;
print "package Human : $Human::animal\n";
print "package Lion  : $Lion::animal\n";
print "package Tiger : $Tiger::animal\n";

違いは print する際に「$human」とだけ書くか、パッケージ名を修飾しているかどうかです。