プログラミング言語では、名前解決とは、プログラム式内のトークンを目的のプログラム コンポーネントに 解決することです。
概要
コンピュータ プログラム内の式は、変数、データ型、関数、クラス、オブジェクト、ライブラリ、パッケージ、およびその他のエンティティを名前で参照します。そのコンテキストでは、名前解決とは、必ずしも一意ではない名前と、意図されたプログラム エンティティとの関連付けを指します。特定のコンテキストでこれらの識別子が参照するものを決定するアルゴリズムは、言語定義の一部です。
これらのアルゴリズムの複雑さは、言語の高度さによって左右されます。たとえば、アセンブリ言語での名前解決には通常、単純なテーブル参照が1 回だけ含まれますが、C++での名前解決は次のような処理が含まれるため、非常に複雑です。
- 名前空間。これにより、識別子は関連付けられた名前空間に応じて異なる意味を持つことができます。
- スコープ では、識別子が異なるスコープ レベルで異なる意味を持つことが可能になり、さまざまなスコープのオーバーライドおよび非表示ルールが伴います。最も基本的なレベルでは、名前解決では通常、最小の囲みスコープ内でバインディングを見つけようとします。そのため、たとえば、ローカル変数はグローバル変数よりも優先されます。これをシャドウイングと呼びます。
- 可視性ルール。特定の名前空間またはスコープの識別子が現在のコンテキストから可視かどうかを決定します。
- オーバーロードにより、単一の名前空間またはスコープ内であっても、識別子の使用方法に応じて異なる意味を持つことができます。
- アクセシビリティは、可視スコープからの識別子が実際にアクセス可能であり、名前解決プロセスに参加できるかどうかを決定します。
静的と動的
プログラミング言語では、名前解決はコンパイル時または実行時に実行できます。前者は静的名前解決と呼ばれ、後者は動的名前解決と呼ばれます。
動的な型付けは動的な名前解決を意味するという誤解が、よくあります。たとえば、Erlangは動的型付けですが、静的な名前解決があります。ただし、静的な型付けは静的な名前解決を意味します。
静的な名前解決は、コンパイル時にスコープ外の変数の使用をキャッチし、プログラマーのエラーを防ぎます。動的なスコープ解決を備えた言語は、柔軟性を高めるためにこの安全性を犠牲にしており、通常、実行時に同じスコープ内で変数を設定および取得できます。
たとえば、Python対話型REPLでは次のようになります。
>>> number = 99
>>> first_noun = "problems"
>>> second_noun = "hound"
>>> # 使用する変数は実行時に決定されます
>>> print ( f "I got { number } { first_noun } but a { second_noun } ain't one." ) I got 99 issues but a hound ain't one.
しかし、コード内で動的な名前解決に依存することはPythonコミュニティでは推奨されていません。[1] [2]また、この機能はPythonの今後のバージョンでは削除される可能性があります。[3]
静的な名前解決を使用する言語の例としては、 C、C++、E、Erlang、Haskell、Java、Pascal、Scheme、Smalltalkなどがあります。動的な名前解決を使用する言語の例としては、一部のLisp方言、Perl、PHP、Python、Rebol、Tcl などがあります。
名前のマスキング
マスクは、重複する語彙スコープ内の異なるエンティティに同じ識別子が使用されるときに発生します。変数レベル(名前ではなく)では、これは変数シャドウイングと呼ばれます。2つの条件が満たされると、識別子I'(変数X')は識別子I(変数X)をマスクします。
- I'はIと同じ名前です
- I'はIのスコープのサブセットであるスコープで定義される
外部変数 X は内部変数 X' によって シャドウイングされていると言われます。
たとえば、次の一般的なパターンでは、パラメータ「foo」がローカル変数「foo」をシャドウします。
private int foo ; // 名前「foo」は外側のスコープ内で宣言されています
public void setFoo ( int foo ) { // 名前 "foo" は内部スコープで宣言されており、関数ローカルです。this . foo = foo ; // "foo" は最初に ''最も内側の'' スコープで検出 (および解決) されるため、 // 属性 "foo" の格納値を入力パラメータ "foo" の新しい値で正常に上書きするために、 // "this.foo" (オブジェクト属性) と "foo" (関数パラメータ) が区別されます。}
パブリックint getFoo () {戻り値 foo ; }
名前のマスキングは関数のオーバーロードに複雑さを引き起こす可能性があります。これは、一部の言語 (特に C++) ではオーバーロードがスコープ間で行われないため、オーバーロードされたすべての関数を再宣言するか、特定の名前空間に明示的にインポートする必要があるためです。
名前解決を簡単にするためのアルファの名前変更
変数名を反映しないレキシカル スコープを持つプログラミング言語では、 α 変換(または α 命名変更) を使用して、包含スコープ内の別の名前をマスクする変数名が存在しないことを確認する置換を見つけることで、名前解決を容易にすることができます。α 命名変更により、言語のスコープ ルールを理解する必要があるのはα 命名者だけなので、 静的コード分析が容易になります。
たとえば、次のコードでは:
クラスPoint { private : double x , y ;
public :
Point ( double x , double y ) { // ここで宣言された x と y はプライベートをマスクしますsetX ( x ); setY ( y ); }
void setX ( double newx ) { x = newx ; } void setY ( double newy ) { y = newy ; } }
Pointコンストラクタ内では、インスタンス変数 xとy は同じ名前のローカル変数によって 隠されています。これは次のように名前が変更される可能性があります。
クラスPoint { private : double x , y ;
パブリック:
Point ( double a , double b ) { setX ( a ); setY ( b ); }
void setX ( double newx ) { x = newx ; } void setY ( double newy ) { y = newy ; } }
新しいバージョンではマスキングがないので、どの使用がどの宣言に対応しているかがすぐにわかります。
参照
参考文献
- ^ 「[Python-Ideas] str.format ユーティリティ関数」 2009 年 5 月 9 日. 2011 年 1 月 23 日閲覧。
- ^ 「8.6. 辞書ベースの文字列フォーマット」。diveintopython.org . Mark Pilgrim . 2011-01-23閲覧。
- ^ 「9. クラス - Python ドキュメント」 。2019年 7 月 24 日取得。
スコープはテキストで決定されることを認識することが重要です。モジュールで定義された関数のグローバル スコープは、関数がどこから、またはどのエイリアスによって呼び出されたかに関係なく、そのモジュールの名前空間です。一方、実際の名前の検索は実行時に動的に行われます。ただし、言語定義は「コンパイル」時の静的な名前解決に向けて進化しているため、動的な名前解決に頼らないでください。(実際、ローカル変数はすでに静的に決定されています。)
