スコープ (プログラミング)
プログラミングにおけるスコープ(英: scope, 可視範囲)とは、ある変数や関数などの名前(識別子)を参照できる範囲のこと。通常、変数や関数が定義されたスコープの外側からは、それらの名前を用いるだけでは参照できない。このときこれらの変数や関数は「スコープ外」である、あるいは「見えない」といわれる。
プログラミングでは、ソースコードの可読性を向上し、また予期しない誤動作を避けるためにも、それぞれの処理段階で必要のない要素の名前はできるだけ参照されないようにすることが望ましい。特に、複数の関数にまたがったスコープを持つことのできるグローバル変数(大域変数)は便利な場合もあるが、どこで参照・変更されているかを常に気にしていなければならず、不用意な変更は危険でもある。たとえば、CERT C コーディングスタンダードには、「変数と関数の有効範囲を最小限にする」(DCL19-C)[1]というレコメンデーションがある。
通例、入れ子になったスコープ階層ごとに同じ名前の識別子が出現したとき、より内側のスコープに属する識別子のほうが優先的に名前解決に使用される。
スコープと生存期間
[編集]スコープとは別に、生存期間あるいは寿命 (lifetime) と呼ばれる概念がある[注釈 1]。スコープは名前の可視性や名前解決について議論されるものであり、生存期間はオブジェクトの有効期間やライフサイクルについて議論されるものである。例えばC言語において、関数内すなわちローカルスコープの変数(ローカル変数)にstatic
キーワード(静的記憶クラス指定子)を付加すると、その変数の可視範囲は関数内かつ所属ブロック内のままで変わらないが、生存期間は変化する。
後述する「動的スコープ」などにも、厳密にはスコープとエクステントの混同がある( https://www.cs.cmu.edu/Groups/AI/html/cltl/clm/node43.html などを参照)。[要追加記述]
スコープの種類
[編集]名前空間からの分類
[編集]- 大域スコープ (global scope)
- プログラムの「全体」から見えるスコープのこと。このスコープに属する変数は、グローバル変数または大域変数といわれる。BASICのような単純な言語では大域スコープしか存在しない場合がある。Pythonのようなグローバル変数の書き換えが簡単には行えない言語も存在する。
- ファイルスコープ (file scope)
- 大域スコープと似ているが、プログラムを記述したファイルの内側でのみ参照できるスコープ。プログラムが複数のファイルから構成される場合は他のファイルから参照することはできない。
- 局所スコープ (local scope)
- ある関数やブロックの範囲内に限定されたスコープのこと。このスコープに属する変数は、ローカル変数と呼ばれる。何を持って範囲を与えるかは言語により様々だが、一般に入れ子のローカルスコープは外側を参照できるのが普通である。このとき兄弟関係にあるスコープは見えない。変数宣言が必要な言語の場合は宣言文以降にスコープが制限される場合が多い。
- C言語およびC++では、関数内において外側のブロックに存在する識別子と同じ名前の識別子を内側のブロックで定義することができ、外側の識別子は内側の識別子で隠蔽されるが、JavaやC#では許可されない。
- インスタンススコープ (instance scope)
- クラスベースのオブジェクト指向言語で、クラスの各インスタンスに割り当てられた変数(フィールド)や関数(メソッド)が、そのインスタンス経由でのみ参照されうるスコープのこと。このスコープに属する変数はインスタンス変数やメンバー変数とも呼ばれ、また関数はメンバー関数とも呼ばれる。インスタンス内で共有されるので、局所スコープよりも可視範囲が広くなる。当該クラスのメソッドの内部でこれらを参照するとき、通例
this
やself
といったオブジェクト参照によりスコープを明示することで、メソッドの仮引数やローカル変数、あるいはローカル関数などと名前が衝突した場合にも区別できるようになっている。 - C言語の構造体メンバー参照なども一種のインスタンススコープである。
- クラススコープ (class scope)
- クラスベースのオブジェクト指向言語で、あるクラスの定義全体から参照できるスコープ。このスコープに属する変数はクラス変数とも呼ばれ、関数はクラスメソッドとも呼ばれる。クラス全体で共有されるので、ある種の制限された大域スコープと考えることもできる。クラス外からこれらを参照するとき、クラス名の修飾によりスコープを明示する。また、当該クラスのメソッドの内部でこれらを参照するとき、通例クラス名の修飾によりスコープを明示することで、メソッドの仮引数やローカル変数、あるいはローカル関数などと名前が衝突した場合にも区別できるようになっている。
- クラススコープをもたない言語の場合でも、ファイルスコープを用いることで同様の機構を実現できる場合がある。
なお、オブジェクト指向言語は通例カプセル化のため、フィールドやメソッドについてアクセス可能な範囲(可視性)を指定できるアクセス修飾子の機能を備えているが、アクセス修飾子によるアクセス制限とスコープの概念は関連があるものの別物である。また、基底クラスで定義されたフィールドやメソッドが派生クラスからもアクセス可能な場合は、それらを参照する際に、C++では基底クラス名を用いた修飾によりスコープを明示するが、JavaやC#ではsuper
やbase
といったキーワードによるエイリアスを使う[注釈 2]。
スコープ導入からの分類
[編集]- 静的スコープ (static scope)
- 字句スコープまたはレキシカルスコープ (lexical scope) とも[注釈 3]。ブロックや関数などの入れ子構造によって静的に可視範囲が導入されるスコープ。
- 動的スコープ (dynamic scope)
- 実行時の動的な呼出の親子関係によって導入されるスコープ。関数が呼び出し元で展開されたかのようなスコープが構成される。実行時に名前による解決が必要なため、普通にコンパイルしてこれを実現するのは面倒である。
- 名前空間 (namespace)
- 厳密にいえば名前空間自体はスコープそのものではなく、スコープを導入する機構である。おおまかに2通りのものを名前空間と呼んでいる。
- 名前の集合を定義するもので、任意のタイミングで名前空間を導入し、定義された名前を参照可能にすることができる。名前空間では持続範囲を指定できるため、外部で必要のない名前の拡散を避けることもできる。名前空間自体も一種のスコープを持ち、名前空間の名前によって参照される。この視点では、上記のファイルスコープやローカルスコープも暗黙の名前空間でスコープを構成していると考えられる。ただし無名であり、外部に導入できない名前空間である。
- ごく単純なプログラミング言語を除いて、たとえば構造体のメンバー名などは、他の名前と干渉せず、その構造体の中でユニーク(唯一)であれば任意の名前が使える(予約語と同一の場合は制限されることもある。字句や構文の都合にもよる)。そのような「名前が干渉せず、区切られている」それぞれの空間を名前空間という。Lispにおける「Lisp-1とLisp-2の議論」などがある。
脚注
[編集]注釈
[編集]- ^ 記憶域期間 (storage duration) あるいはエクステント (extent) とも。
- ^ Microsoft Visual C++では、独自拡張として
__super
キーワードによるエイリアスをサポートしている。 - ^ lexical は「字句の」「語彙の」といった意味を持つ英語の形容詞。
出典
[編集]- ^ DCL19-C. 変数と関数の有効範囲を最小限にする2023年9月3日閲覧。