[プログラミング]スコープとは‐動的スコープ‐

VBA

どうも。つじけ(tsujikenzo)です。このシリーズではプログラミング言語の「スコープ」について全3回でお届けしています。今日は第2回目で「動的スコープ」についてです。

前回のおさらい

前回は、「プロジェクトと名前」についてお届けしました。変数を定義したら「変数名対応表」という架空の管理表にメモをして、プロジェクト全体から参照しました。1枚の変数名対応表を参照すればいいので楽でしたが、今度は「名前の衝突」問題が発生しました。

[プログラミング]スコープとは‐プロジェクトと名前‐
どうも。つじけ(tsujikenzo)です。このシリーズではプログラミング言語の「スコープ」について全3回でお届けします。今日は第1回目で「プロジェクトと名前」についてです。現在ノンプロVBA中級講座2期を受講していますが、VBA...

今回は「動的スコープ」についてお届けします。

よっこする

北海道の方言で「よっこする」という言葉があります。「よけておく」という意味です。これは「通路に邪魔だからよっこして」というニュアンスより「後で食べる分はよっこしといたからね」といった風に、邪魔なものを片付けるという意味ではなく「大切なものだから影響を受けないように保護しておく」という意味が強いです。

前回、変数nameに値”Tsujike”を代入して、[変数名対応表]にも記入しました。

6行目の関数myFunction()をコメントインして、実行すると、変数name = ‘高橋’が上書きされますので、その流れも「変数名対応表」にもメモしておきました。

ここで、元からあった変数name = ‘Tsujike’が上書きされないように、myFunction()が実行さるときによっこしてみます。

具体的には、

  1. 変数oldNameを用意する
  2. 変数oldNameに変数nameを代入する
  3. 最後の処理で変数nameに変数oldNameを戻す

という処理です。これで、変数name = ‘Tsujike’はよっこされています。

コード.gsファイルの関数getName()を実行しても、変数nameは’高橋’に変更されていないことが分かると思います。

この流れを「変数対応表」にメモしています。

この、関数の入り口でよっこして、出口で戻す処理のことを「動的スコープ」と呼びます。

「スコープ」とは変数が使える範囲を指し、「動的」とは「一度よっこしたものを後で戻す」(変数の範囲が時間軸なので動的である)という意味です。

動的スコープの変数名対応表

さきほど、6行目のmyFunction()が実行されたときに、変数nameをよっこしたことを「変数名対応表」の下部に「追記」しました。

これ、「追記」ではなく、新しい変数名対応表「変数名対応表:動的スコープ(仮)」を作成するアイディアはいかがでしょうか。

6行目のmyFunction()が実行されたときに、「変数名対応表」の上に、もう一枚レイヤーが追加されるイメージです。

新しい「変数名対応表」を作成したことで、myFunction()内ではよっこする必要がなくなります。

詳しく説明します。この「変数名対応表:動的スコープ(仮)」は、myFunction()の中で「変数が定義されたら新規作成」され、myFunction()を「抜けた後は破棄」されます。

プロジェクト全体のどこからでも見ることができますが、存在するのはmyFunction()を実行している間だけです。

これまでの流れの確認

変数は、定義されると「変数名対応表」が作成され、メモされます。プロジェクト内のどこからでも参照することができます。

例えば、7行目のmyFunction()が呼び出されて、変数が定義されると、新規「変数名対応表:動的スコープ(仮)」が作成されます。

myFunction()を抜けるまでは変数の定義は「変数名対応表:動的スコープ(仮)」にメモされますし、変数の呼び出しも、まずはこの「変数名対応表:動的スコープ(仮)」を確認します。「レイヤーが一枚重なっている」というイメージを持ってください。

呼び出しの際に「変数名対応表:動的スコープ(仮)」に変数が無ければ、レイヤーを一枚めくって、「変数名対応表」に変数があるか確認します。

(このレイヤーを一枚めくる動作を「グローバル変数、またはパブリックモジュールレベル変数の参照」と呼びます。)

これが「動的スコープ」です。

動的スコープの問題点

動的スコープを導入したことにより、変数nameと同じ名前の変数name = ‘高橋’を定義しても、もともとあった変数name = ‘Tsujike’に影響を与えなくなりました。

しかし、関数getName()の中で変数nameを定義して、関数getName()を実行すると、新しい[変数名対応表:動的スコープ(仮)]が作成される①ため、

9行目②でこのようなmyFunction()が実行されると、Etauが返ります。

もちろんmyFunction()を単体で実行すると、[変数名対応表:動的スコープ(仮)]は存在しませんので、Tsujikeを返します。

このように、ある関数を呼び出すとき、別の関数ですでに作成された[変数名対応表]がある場合は、呼び出した先の変数で影響を受けてしまいます。

さらに、元の変数には何が定義されていたのかが見えなくなってしまいましたし、元の関数を見にいかないと、何が定義されていたのかわからなくなってしまいました。

呼び出した先の変数に影響を与えないようにできないものでしょうか。

また、変数名がこの先で重複していないかどうか、プロジェクト全体を気にしてコードを書かなくてもすむ方法はないのでしょうか。

まとめ

さて、今日は「動的スコープ」についてまとめました。いったん受け取った変数を「よっこする」という方法で、元の変数に影響を与えない工夫をしました。

具体的には、一つ上のレイヤーを一枚重ねるように、[変数名対応表:動的スコープ(仮)]を作成する方法です。

しかし、[変数名対応表:動的スコープ(仮)]はプロジェクトのどこからでも参照できるため、[変数名対応表:動的スコープ(仮)]が存在すると、「変数名対応表:動的スコープ(仮)内に同じ名前の変数があった場合、そちらを優先的に参照してしまう」という問題が出てきました。レイヤー構造をイメージするとわかりやすいと思います。

次回は「静的スコープ」でこの問題を解決します。

このシリーズの目次

  1. [プログラミング]スコープとは‐プロジェクトと名前‐
  2. [プログラミング]スコープとは‐動的スコープ‐
  3. [プログラミング]スコープとは‐静的スコープ‐
タイトルとURLをコピーしました