大域変数の有効範囲

大域変数について

 大域(グローバル)変数はgoto文とともにbasic(に限ったもんでもないですが)のロクでもない仕様の一つとされています。AppleScriptの場合の場合は、変数が全て大域変数というわけでは無いので被害は少ないのですが、大域変数は根本的な問題が多くあります。
 問題を回避することを考えるより、大域変数は使わないですます方が圧倒的に楽です。
 これ以降の文は、大域変数がおこす問題を回避する方法を書いている訳ではありません。大域変数がおこす問題を回避するのがいかに面倒であるかを書いているのです。

基本的な法則

 大域変数は宣言と定義によって成立する。
 宣言とは

global x

である。  定義とは変数に値を代入することであり、

set x to 1

もしくは

copy 1 to x

という形になる。
 有効とは、その範囲で大域変数として使えるということ。

 ということを踏まえて、大域変数の法則を並べると、次のようになります。

  1. 同名の大域変数は共有される
  2. 同名の属性と共有される
  3. 有効な場所であれば、定義はどこでもよい
  4. 同名の局所変数が宣言されているハンドラでは無効
  5. トップレベルのrunハンドラの変数は暗黙で大域
  6. トップレベルで宣言しているものはスクリプト全体で有効
  7. SOのトップで宣言されるとSO内で有効
  8. ハンドラで宣言されているとハンドラ内で有効
※スクリプトオブジェクトはSOと表記

 ここでは取り上げていないのですが、load scriptでスクリプトオブジェクトを読み込んだ場合や、ハンドラの呼び出しによってスクリプトオブジェクトを定義している場合など、さらにややこしい事になってしまいます。
 大域変数を使うと、迂闊にスクリプトオブジェクトが使えません。

問題はどこだ

 第一に問題なのは、トップレベルで宣言しているものはスクリプト全体で有効ってことで、スクリプトオブジェクトの中も完全に有効範囲に含まれてしまいます。
 load script命令を使用しているスクリプトでは、トップレベルでの大域変数宣言は絶対に避けた方がいいでしょう。

 次に、トップレベルで宣言していない場合でも、スクリプトオブジェクトが変数の有効範囲として、独立していないということです。
 スクリプトオブジェクトの外で、変数の内容が勝手に書き換えられてしまう可能性があるのは、いくら何でもカプセル化が弱すぎます。これではオブジェクト指向のメリットがありません。
 ただし、大域変数を一切使わなければ、そもそも問題は発生しませんから、スクリプトオブジェクトが使い物にならない訳ではありません。

 また、利用者定義属性と大域変数が共有されてしまうのも困ったものです。
 大域変数を変更すると、何故か利用者定義属性が変更されてしまうのですから、たまったものではありません。
 どうやら、AppleScriptの内部では、利用者定義属性と大域変数は同じプログラムで管理されているようです。

トップレベルで宣言していない場合

●global宣言箇所
赤色-同名の大域変数が有効となる箇所

トップレベル
├ runハンドラ
├●runハンドラ
├ ハンドラ
├●ハンドラ

├●スクリプトオブジェクト(トップ)
│├ ハンドラ
│└●ハンドラ

└スクリプトオブジェクト(トップ)
 ├ ハンドラ
 └●ハンドラ

 トップレベルで宣言していない場合、runハンドラを除き、大域変数宣言を行わない限り、大域変数とはなりません。
 といっても、宣言してしまえば、同じ変数として値が共有されるのに代わりはありません。利用者定義属性(property)ならば、スクリプトオブジェクトの外と共有されることはありませんから、大域変数を使うぐらいならば、利用者定義属性を利用した方がいいでしょう。ただし、利用者定義属性も極力使わない方がいいでしょう。

トップレベルで宣言している場合

●global宣言箇所
赤色-同名の大域変数が有効となる箇所

●トップレベル
├ runハンドラ
├●runハンドラ
├ ハンドラ
├●ハンドラ

├●スクリプトオブジェクト(トップ)
│├ ハンドラ
│└●ハンドラ

└スクリプトオブジェクト(トップ)
 ├ ハンドラ
 └●ハンドラ

 要するに、トップレベルで宣言してしまうと、全ての場所で同名の変数(属性)は有効になり、同じ値が共有されます。


2001-01-15 -2001-07-25