今回は、プログラミングの世界ではとかく嫌われがちな「グローバル変数」について考えてみたいと思います。
「グローバル変数」という用語は、どこからでもアクセスできる変数程度の意味で使われています。しかし、プログラミング言語によっては、明確に定義されているものもあれば、そうでないものもあります。
そもそも「グローバル」とは何でしょうか? 「変数」とは何でしょうか? 「どこからでも」とは具体的にどういうことでしょうか? 「アクセスできる」とは具体的にどのようなことでしょうか?
これからいくつかのプログラミング言語について考えてみることにしましょう。
PHPの場合
PHPのマニュアルには、「グローバル変数」の記述が何度も登場します。主に「変数のスコープ」のページで記述を見るけることができます。PHPの「グローバル変数」とは何かについては、他のページの記述も参照しつつ、私なりに次のように理解しています。
グローバル空間において、関数の外部で定義された変数
PHPのグローバル変数は、関数内ではglobalキーワードを用いて参照することができます。
ここでひとつ疑問が湧いてきます。グローバル空間ではなく何らかの名前空間で定義した関数の中でglobalを使うと、その名前空間の中の変数を参照することになります。だとすると、グローバル空間になくても関数の外で定義している変数ならグローバル変数なのかもしれません。
C#の場合
C#では、グローバル変数が存在しないことが明確に規定されているようです。
クラスや構造体のメンバーは、public staticにすれば他のクラスからだろうが他のアセンブリからだろうがアクセスできるのですが、これはグローバル変数ではないそうです。本当にそれでいいんでしょうか?
Javaの場合
Javaの言語仕様には、global variable(s)の記述は1箇所しか見つけることができませんでした。しかも、「shared global variables」という形でです。
これは、スレッド間の共有メモリに関する話で、スコープに関する話ではないように思います。「どこからでも」アクセスできるという観点からは、どんなスレッドからでもアクセスできる必要があるかもしれませんけど。
ECMAScriptの場合
ECMAScriptの言語仕様には、global variable(s)の記述は見つかりませんでしたが、The Global Objectという章がありました。
ただ内容を見てみると
コレじゃない感が伝わってきますね。
Cの場合
グローバル変数がどうのこうのいわれるのは何といってもCを使う場合ですので、Cについても考えてみましょう。
Cの言語規格でも調べてみましたが、global variable(s)が登場するのはC99でもC17でも1箇所だけでした。「浮動小数点環境のフラグやモードはグローバル変数とみなす」といった内容です。これは、Cのオブジェクト(普通は「変数」と呼ばれます)ではなく、プロセッサステータスワードや制御レジスタといったハードウェア上のリソースのことです。
また、C11やC17では、浮動小数点環境はスレッド記憶域期間(thread storage duration)を持つことが明記されています。さっきのJavaの話とはかなりずれてきましたね。
C++の場合
C++の言語仕様にも、global variable(s)の記述は1箇所だけ見つけることができました。エラー番号の格納先、つまりerrnoの参照先のことでした。
errnoの具体的な仕様はC規格に振っていますが、これは単なるマクロです。マクロがどのように展開されるかは当然処理系定義です。C11やC17では、errnoの参照先はスレッド記憶域間であるとされていますが、C++14が参照しているのは確かC99ですのでこの辺りがあやふやになります。
いくつかの言語を具体的に挙げながら「グローバル変数」がどのように扱われているかを見てきました。結果、言語によって扱われ方はマチマチで、こんな状況では「グローバル変数」とは一体何なのか、統一的な考え方を導くのは困難です。
多くのコーディング規約ではグローバル変数の使用を禁止、または制限しています。しかし、そもそも「グローバル変数」とは何かを定義しない限り、このようなあいまいなルールを守ることを約束することなどできそうにありません。
C#が主張するように、クラスや構造体のメンバーなら「グローバル変数」ではないのでしょうか? 特定の名前空間で定義した場合はどうなのでしょうか? スレッドローカルな場合は「グローバル変数」ではないのでしょうか? プロセスの外からアクセスできなければ「グローバル変数」ではないのでしょうか?
「どこからでも」というのは本当にあいまいです。字義通りに解釈すれば、コンピュータの外だろうが、何万パーセク離れた天体だろうが、どんな場所でも対象になるはずです。常識的に判断したいのはやまやまですが、妥当な線引きはできそうにありません。
「アクセスできる」もあいまいですね。直接読み書きできなくても、アクセッサを介して読み書きできるのであれば、それは「アクセスできる」ということではないでしょうか?
実際、errnoマクロを介して読み書きするエラー番号の格納先なんかは完全にそんな感じですよね?
「グローバル変数」のようなあいまいな用語は便利ですが、コーディング規約などのルールを定める際には、それが一体何を意味するのか、明確に定義しなければ意味をなしません。