名前空間
名前空間(なまえくうかん)はNamespaceの訳語で、名前の集合を分割することで衝突の可能性を低減しつつ参照を容易にする概念である。
この集合は、全事象の元の全ての組み合わせ可能なものからなる集合全体および物理的な名称を指すことが可能である。つまり英字・数字・記号などを組みあわせて作られる名前全てを含む集合である。名前に結び付けられる実体(型や変数)は、名前がそれぞれどの集合(空間)に属するか指定されることで一意に定まる。名前空間が異なれば同じ名前でも別の実体に対応付けられる。
たとえば「一郎」という人名は日本中に何人もいるため、ひとりの人間に特定することはできない。このように、同一の名前のものが複数存在し、その区別がつかない状態を名前の衝突(名前の競合)と呼ぶ。しかし、「鈴木一郎」とフルネームで呼ぶことにより他の「佐藤一郎」や「山本一郎」といった人とは区別でき、名前の衝突を避けることができる。このとき「一郎」を単純名、「鈴木一郎」を完全限定名と呼ぶ。人名「一郎」は名前空間「鈴木」に属していると捉えることができる。また、同じ「鈴木」という姓である鈴木家の家族間では、「一郎」は暗黙的に「鈴木一郎」のことであると解釈されるため、わざわざ完全限定名の「鈴木一郎」で呼ぶ必要がない。また、予め「『一郎』とは『鈴木一郎』のことである」と宣言しておけば、その後単純名で「一郎」と呼んでも暗黙的に「鈴木一郎」だと解釈されるため、シンプルな「一郎」のみで呼ぶことができる。必要なら、「日本国東京都世田谷区○丁目○○鈴木一郎」と呼ぶことで、同姓同名の人間とも区別することができる。これらの考え方は名前空間の概念に近いものである(これは分かりやすく説明するための方便であり、名前空間とは厳密にはイコールではない)。
ここでは、名前空間はソースコード上で冗長な命名規則を用いなくても名前の衝突が起こらないようにし、しかもそれを容易に記述できるようにするためだけの概念であり、普通はそれ以上の意味は持っていない(上記の地名のたとえは行政上の管轄としての意味合いがあるが、プログラム言語の名前空間には一意な名前という以上の意味合いはない)。Javaの機能、「パッケージ」では名前空間とアクセス制限、ソースファイルのディレクトリ構造の表現の機能を統合しているが、C++やC#の「純粋な」名前空間はクラスやそのメンバのアクセス制限とは無関係である。Cには名前空間を複数に分割する機能が無く、名前の衝突を避けるためにはなんらかの命名規則を用いる必要がある。
通常は文脈によって定まる名前空間が暗黙に指定される。指定したい実体に対応する名前が他の名前空間にある場合は、名前空間と名前を明示的に組み合わせることで一意に特定できる。たとえば名前bazは集合Aの中ではデータ型を表し、集合Bでは変数を表すというように指定する。
次はJava/C#用の擬似コードによる例である。
void baz() {}
int baz;
void Main() {
baz = 100;
}
この例では同じbazという名前を持つ関数と変数が宣言されているが、関数と変数の名前空間は暗黙的に分けられているので名前の衝突は起こらない。関数Main内に記述された名前bazには=演算子によって数の代入がされており、処理系はそれが変数名であると推定できる。ただし、C/C++やSchemeなど関数名と変数名の名前空間が分けられていない言語もあり、そのような言語では同じ名前で再定義された時点でエラーになるか、値が束縛された名前で関数を呼び出そうとするとエラーになる。上の例の変数名と関数名のように、文脈によって暗黙に名前空間が区別できるならば(それが望ましいかどうかは別として)同じ名前を使用することができる。しかし、一つの名前空間の中で同名の関数を定義すると問題が発生する。次のように同じ名前の関数、Hogeを二つ定義したとする。
void Hoge() {}
void Hoge() {}
void Main() {
Hoge();
}
この場合、二つ目のHoge関数が定義された時点で、処理系は多重定義としてエラーを出す。特に複数のチームで開発を行っていると名前の衝突が起きやすい。次の例は、別々のチームで書かれた二つの関数Hoge()の名前の衝突を避けるため、関数名の先頭に「チーム名_」とつけるように取り決めた場合のものである。
void TeamA_Hoge() {}
void TeamB_Hoge() {}
void Main(){
TeamA_Hoge();
TeamB_Hoge();
}
これでも名前の衝突は避けられるが、呼び出しでは常にチーム名まで含めた名称で記述しなければならないため、記述も面倒でソースコードは読みにくくなってしまう。また、両方の関数をincludeしないような時には名前の衝突は起こらず、せっかくの命名規則も取り越し苦労に終わってしまう。このような場合は、2つのクラスHogeを別々の名前空間に入れる。
namespace TeamA {
void Hoge() {}
}
namespace TeamB {
void Hoge() {}
}
void Main() {
TeamA.Hoge();
TeamB.Hoge();
}
こうすると、上の関数Hogeの名前はTeamA.Hoge、下の関数Hogeの名前はTeamB.Hogeとなり、両者を区別できるようになる。複数のチームで開発を行う場合は、チームごとに使用する名前空間を決めておけば名前の衝突は起こらないので、それぞれのチームが自由に名前を付けることができる。しかし、ひとつのソースコード中でTeamA.HogeとTeamB.Hogeの片方だけを使う場合は、完全限定名での記述は冗長な表現となってしまう。そのような場合は、C++やC#ではusingキーワードを使うことで、単純名のみの記述が使える。
using TeamA;
void Main() {
Hoge();
}
処理系はusingディレクティブから単純名Hogeの完全限定名がTeamA.Hogeであることを推定し、単純名Hogeは完全限定名TeamA.Hogeに補完されてコンパイルが成功する。また、同一の名前空間内からの呼び出しでは単純名は自動的に補完されるため、常に単純名で記述することができる。下の例では、関数Hogeと関数Mainは同一の名前空間TeamAに属しているため、関数Mainからは単純名での記述で関数Hogeを呼び出すことができる。
namespace TeamA {
void Hoge() {}
void Main() {
Hoge(); //TeamA.Hogeの呼び出しだとみなされる
}
}
これら名前空間およびそれに付随する概念は、プログラミング言語に限らず活用されている。例えば、EメールアドレスやURIも名前空間と同等の論理で組み立てられていることはよく知られており、このような命名の仕組みによって名前を区別、分類するようなものを、広く名前空間と呼ぶこともある。
URIのスキームの名前空間はIANAが管理している。
XMLの名前空間は、要素名などが重複することのないように整理された空間。xmlns属性などで名前空間を宣言する。例えば、「<html:p>」と記述されたタグでは、「html」が名前空間接頭辞で「p」が要素名を表す。
ウィキペディアを含むの使用サイトにおいては、Help:名前空間のようなページの種類を区分する名前空間の一覧がある。例えば「Help:名前空間」という項目名においては、「Help」が名前空間、「名前空間」が名前である。この記事自体が、同名の項目でも、名前空間により書かれている内容が異なるものの一例として挙げることができる。