俺による俺のためのオブジェクト指向講座。その3

そんなこんなで日が開いたけど第三回。
実際に実装しながらPerlOOPをやる上での概念的な何かを紹介していく。

名前空間というもの

第一回でポチの例を出した「名前空間」。
うちのポチと隣の家のポチは違うポチだという程度しか説明していないので改めて。

上記の例で言いたいのは、「同じ名前(ポチ)であっても、その名前を使う空間(家)によって違うもの(犬)を表している」ということ。
逆に言えば、同じ空間で同じ名前を使うと同一のものを指し示すことになるということ。

これがプログラムにどう関係するかというと。

コード上で「名前」が付くものといえば、まず第一に「変数」があり、また「関数(サブルーチン)」がある。
普通、コード上で同じ名前を使うと元々あった名前の場所に上書きされる。

$x = 1;
print $x; # 1

$x = 2;
print $x; # 2

サブルーチンも同様に

no warnings 'redefine';

sub foo {
  print 'Foo';
}

sub foo {
  print 'Bar';
}

foo(); # Bar

とかいうことになる。
後者の例は書き方があまりにもアレだけど、「モジュール化」なんつってファイルをあちこちに分け始めるとこういうことが起こる。
つまり同名の関数を定義してしまうと。

これが個人レベルならまだ対処のしようもあるけど、複数人で協力するようなプロジェクトだと大変。

「やあボブ。君はfooなんて関数を作っちゃいないだろうね?」
「何言ってるんだジョン。先週俺はfooって名前を使うぞって確認したじゃないか」
「いや、僕は聞いてないよ。君が言い忘れたんじゃないのかい?」

(´・ω・`)みたいな会話が成立し(ry

とにかくそんな感じにして名前空間の汚染」と呼ばれる事態が起こる。
予期しない内容で定義済みの変数や関数が上書きされてしまうことになる。
このような「名前の衝突」を回避する方法が、「名前空間」の宣言だ。

名前空間を宣言する

package MyApp;

このように記述した行以下は、MyApp名前空間に属するものとして扱われる。
範囲は、宣言したブロックの終わり(次のpackage宣言、{}の終わり、__END__ブロック、ファイルの終わり)まで。

何も宣言されていない場所はデフォルトでmain名前空間に所属するものとして扱われる。

#!/usr/bin/perl

$a = 1;
print $a; # 1

package MyApp;

print $a; # 何も表示されない

この例では、mainパッケージで$aという変数を宣言し、その内容を出力している。
次に現在のパッケージをMyAppに変更し、そこでも$aの内容を出力しているが、何も表示されない。
つまり、MyAppという空間には$aという変数が存在していない
あくまで宣言されたのはmain空間の中の$aに過ぎないということだ。

こうすることで、MyApp空間の中では、他の空間の状態を気にすることなく、自由に変数や関数の名前を使うことができる

完全修飾名

MyAppには$aが存在していないが、MyAppから$aという変数を操作することはできる。
「うちのポチ」はいなくても「お隣さんのポチ」と言うことはできるのと同じこと。

#!/usr/bin/perl

$a = 1;
print $a; # 1

package MyApp;

print $main::a; # 今度は1と出る

肝は「$main::a」のところ。
「パッケージ名::」(半角コロン2つ)というのは「(パッケージ名)の〜」という修飾子だ。
これを付けることによって外部の名前空間にアクセスすることができる。
読み書きともに可能。

何も付けないとカレントのパッケージとみなされる。
つまり「名前空間を宣言」の例は

#!/usr/bin/perl

$main::a = 1;
print $main::a; # 1

package MyApp;

print $MyApp::a; # 何も表示されない

と書いたのと同じことになる。

このようにパッケージ名を変数に付ける書き方を「完全修飾名」と呼ぶ。

というわけで

長くなったので続きは次回。