どうも。つじけ(tsujikenzo)です。このシリーズではプログラミング言語の「スコープ」について全3回でお届けします。今日は第1回目で「プロジェクトと名前」についてです。
現在ノンプロVBA中級講座2期を受講していますが、VBAに限らず、ほとんどの中級講座で序盤に立ちはだかるのが「スコープ」です。中級講座は後半になればなるほど勾配がきつくなっていきますので、しっかり足場を固めて山を登っていきましょう。
プロジェクト
私も、全てのプログラミング言語を習得したわけではありませんが、共通して言えることはプログラム全体のことを「プロジェクト」と呼ぶことです。
VBAのプロジェクト
VBAではBookごとに[新規プロジェクト]が生成されます。VBEでプロジェクトを確認すると、Microsoft Excel Objectsというフォルダの中に[Sheet1]や[ThisWorkbook]といったオブジェクトが確認できます。
さらに、プロジェクトにはBookやSheetオブジェクトに限らず、[標準モジュール]や[クラスモジュール]を追加することができます。
GASのプロジェクト
GASでは[スタンドアロンスクリプト]、もしくは[コンテナバインドスクリプト]が1つのプロジェクト単位になっています。
GASのプロジェクトは[json][gs][html]の3種類のファイルで構成することができます。
Pythonのプロジェクト
Pythonは実行環境にもよりますが、Pythonを構成するフォルダや、スクリプトを書く[py]ファイルやテキストファイルなど様々なファイルが格納された「フォルダ」がプロジェクトと呼べるかもしれません。
この「プロジェクト」という単位は是非覚えておきましょう。私たちがプログラミングを書く時は、プロジェクト内に最低1つのスクリプトファイル(VBAではモジュール)を用意してコードを書くことになります。
名前
何かを示すとき「名前」があると便利です。もし、プロジェクトを指すとき、「あの月ごとのシートが入ったExcelに集計用のマクロを書いたやつ」というより「VBAProject(Book2)」と呼んだ方がわかりやすいです。(プロジェクトのことを名前で呼ぶことは少ないと思いますが。)
同じように、変数や関数(プロシージャ)に名前を付けるのは、「見つけやすい、呼びやすい」からです。ノンプロ研GAS中級講座2期卒業LT『参照渡しと値渡し』では、「変数へ代入するとはメモリアドレスを割り当てること」という発表をしました。
コンピュータ上では全ての値は2進法(0か1)で表現され、その値をメモリアドレスに格納しています。さらにメモリアドレスは0x0000E008のような数値と英語の組み合わせで表現されており、人間にはとても読み辛いですし管理できません(だいぶ説明を省略してます)。そこで、「メモリアドレスに名前を付けましょう」というのが変数(定数)です。
例:数値の100はメモリアドレスの0x0000E008~0x0000E020です。 メモリアドレスの0x0000E008~0x0000E020を2倍にしてログ出力しましょう。 [VBA] Dim x as Long: x = 100 x * 2 Debug.Print x [Javascript] const x = 100; x * 2 console.log(x) [Python] x = 100 x * 2
100をあらわすメモリアドレスのことを、変数[ⅹ]という名前をつけると、読みやすくなりましたね。
変数名対応表
前項で「1つのプロジェクト内に最低1つのスクリプトファイルを用意して、プログラムを書く」という説明をしましたが、スクリプトファイルが1つなら「x,y,z」のような変数を用意すればいいです。
アルファベットをaからzまで使い終わったら、次は変数名は「xx,yy,zz」でもいいですし、「x1,x2,x3」でもいいです。
ただし、1つのスクリプトファイルにコードを書いていくと、10~20行だったのが、300~500行ぐらいになってきて、必ず長くなっていきます。人間の記憶力も大変です💦
変数が多くなってきたら、どうやって管理したらよいでしょうか。
ひとつのアイディアとして、どの変数にどんな値が代入されているのか管理するために、「変数名対応表」を用意して変数を定義したら書き込む、というのはいかがでしょうか。(私の架空の話ですのでイメージとしてお聞きください。)
[GAS]
「変数名対応表」を用意しました。これは、別のスクリプトファイル(コード2.gs)からも参照することができます。
VBAでも確認しましょう。VBAでは値の代入はモジュール内で行いますので、Public宣言と型の定義しておきます。「変数名対応表」には型の情報をメモしておきます。
「Public宣言」とは、変数名対応表をどのモジュールからでも参照できるようにしますよ、という呪文です。
別のモジュール(Module2)から「Name、age、msg」に値を代入したり出力するコードを書いて実行してみましょう。下記のように型の宣言をする必要がありません。これは「変数名対応表」に書かれている型の宣言を参照できるからです。
つまり、プロジェクトに1つの「変数名対応表」を作成すれば、プロジェクト内のどのスクリプトファイルからでも呼び出せる変数を作成することができます。便利ですね。
ユニークな名前と名前の衝突
「変数名対応表」を作成すれば、プロジェクト内のどこからでも呼び出せるので便利でした。しかし、プロジェクト内で同じ変数名を使用しないために、[Name1]や[Name2]のような連番を付ける必要があるのでしょうか。
[Javascript] const name122_20210123_tsuji = animal65 + type3_2; console.log(typeof name122_20210123_tsuji.toString())もし、プロジェクト内で同じ変数名を使うと、どのような弊害があるのか、実験してみましょう。
[GAS][コードjs]ファイルの関数getName()を実行すると、予想通りの結果を返します。
しかし、6行目に[myFunction()]を追加すると、結果が「高橋は35歳です」になってしまいます。
myFunction()とは、なにをしているのでしょうか。次で確認してみます。
実は、myFunction()は[コード2.gs]ファイルに書かれており、変数[name]の値を[‘高橋’]に書き変えていました💦
この一連の流れを「変数名対応表」にメモしてみました。
このように、プロジェクト内、特に別のスクリプトファイルで同じ変数名が使われているときは、「変数名対応表」で状況を説明したり、値が変わってしまう条件を書いておく必要がありそうです。
これが[名前の衝突]問題です。1枚の「変数名対応表」では、とても管理が大変そうですね。どうやって問題を解決するのが良いでしょうか。。。
まとめ
さて、「スコープ」の第1回目として「プロジェクトと名前」についてお届けしました。前半は「プロジェクト」について、後半は「ユニークな名前」「名前の衝突」問題を取り上げました。
はじめは、変数を定義した際に「変数名対応表」を1つ作成し、それをプロジェクトのどこからでも参照すれば楽でした。
しかし、名前(変数名)が重複しないように、もしくは重複するなら、その条件をメモするなり、管理する必要が出てきました。
次回は「動的スコープ」でその問題を解決していきます。