グローバル変数、ローカル変数


 HyperTalk では普通の変数はハンドラ内で宣言なしで使えました。例えば

on mouseUp
  put "Hellow" into abc
  put abc
end mouseUp
 というスクリプトでは、変数 abc は mouseUp ハンドラ内だけで有効です。他のハンドラで変数 abc を使った場合は、「名前は同じだけど全く別の変数」として扱われます。この変数はハンドラを終了すると完全に消えて無くなります。

 またハンドラ内で global キーワードを使って、グローバル変数を宣言することが出来ます。
on mouseEnter
  global abc
  put "Hellow" into abc
end mouseEnter

on mouseUp
  global abc
  put abc
end mouseUp
 この2つのハンドラで使われている abc は完全に同一の変数です。グローバル変数は HyperCard を終了するまで有効で、HyperCard を終了すると完全に消えて無くなります。


−−


 Revolution ではこれらの変数タイプをサポートしており、全く同じように使うことが出来ます。更にいくつかのオプションがあります。


 グローバル変数:

 Revolution のグローバル変数は、ハンドラの外で宣言することが出来ます。
global abc

on mouseEnter
  put "Hellow" into abc
end mouseEnter

on mouseUp
  put abc
end mouseUp
 この2つのハンドラで使われている abc は、完全に同一の変数です。スクリプトの先頭で1回宣言するだけで、そのオブジェクト内の全てのハンドラに適用されます。ハンドラ内でいちいち宣言する面倒が無い代わりに、この宣言のあるオブジェクト内では、同じ名前の「普通の変数」が使えなくなります。
 他のオブジェクトのスクリプトに同じ宣言があれば、そのスクリプト内でも同じ値を共有することが出来ます。
 グローバル変数の値は Revolution (またはスタンドアローン)を終了するまで保持されます。 

 もしハンドラ内で global 宣言を行うと、HyperTalk と同じタイプのグローバル変数になります。つまり global 宣言を行ったハンドラ同士でのみ共有する変数です。



 ローカル変数:

 HyperCard の変数はハンドラ内のみ有効の言わば「ハンドラ変数」でしたが、Revolution には「オブジェクト内有効」の「ローカル変数」があります。
local abc

on mouseEnter
  put "Hellow" into abc
end mouseEnter

on mouseUp
  put abc
end mouseUp
 この2つのハンドラで使われている abc は、完全に同一の変数です。ローカル変数を使うには local 宣言が必要です。
 他のオブジェクトのスクリプトに同じ宣言があっても、それは別のローカル変数です。ローカル変数が有効なのは、あくまでその宣言のあるオブジェクト内のスクリプトだけです。
 ローカル変数の値はスクリプトを編集するまで、或いは Revolution(またはスタンドアローン)を終了するまで保持されます。

 もしハンドラ内で local 宣言をすると、そのハンドラ内だけで有効なローカル変数になります。
on mouseEnter
  local abc
  put "Hellow" into abc
end mouseEnter

on mouseUp
  local abc
  put abc
end mouseUp
 この2つのハンドラで使われている abc は、全く別の変数です。普通の変数と違うのは、中身が empty に初期化されることです。このスクリプトを実行するとメッセージボックスには empty が入りますが、local 宣言をしていなかった場合はメッセージボックスに "abc" が入ります。
 empty ではなく別の値に初期化することも出来ます。
local abc = "Hellow"


 カスタムプロパティ:

 Revolution には SuperCard と同じような「カスタムプロパティ」があります。ユーザーがオブジェクトのプロパティを「作る」機能です。これを一種の変数のように使うことも出来ます。変数と違うのは、スタックを保存すれば、その値も一緒に保存されることです。ただし Revolution ではスタックの保存が少々面倒なので、SuperCard ほどには便利に使えないかも知れません。ああクロスプラットフォームは辛いのぉ。



 参照渡し:

 これは変数のタイプと言うより、「引数」のタイプです。

 通常、ハンドラや関数に値を渡すときは、その値のコピーが渡されます。
on mouseUp
  put 1 into a
  put 2 into b
  put tasu( a, b ) into kotae
end mouoseUp

function tasu x, y
  return x + y
end tasu
 tasu関数のxとyには、aの内容とbの内容がそれぞれ「コピー」されます。aとx、bとyは値は同じですが、当然ながら全く別の変数です。

 これに対して参照渡しは、変数のアドレスを渡すものです。
on mouseUp
  tasu a, b, kotae
end mouoseUp

on tasu x, y, @z
  put x + y into z
end tasu
 @zという見慣れない表記の引数が現れ、functionではなくonハンドラになりました。tasuハンドラのxはaのコピー、yはbのコピーですが、zはmouseUpハンドラのkotaeと「完全に同一の変数」です。呼び名は違ってもメモリ上の全く同じ変数領域を使います。そのためtasuハンドラでzに書き込んだ値は、mouseUpハンドラのkotaeに反映されます。

 このヤヤコシイ引数形式が何のためにあるかと言えば、上記のように「渡した変数の中身を他のハンドラで書き換えたい」ためです。関数で返せばいいじゃないか、という考え方も出来ますが、関数が返すことが出来る値はひとつだけです。参照渡しを使えば、例えばこんなことも出来ます。
on mouseUp
  get keisan( a, b, tashita, hiita, kaketa, watta )
end mouoseUp

function keisan x, y, @added, @subtracted, @multied, @dived
  if ( y = 0 ) then return false
  put x + y into added
  put x - y into subtracted
  put x * y into multied
  put x / y into dived
  return true
end keisan
 ほら、一気に4つの値を得ることが出来ました。このように複数の返値が欲しいときは、参照渡しは絶大な威力を発揮します。ここでは関数形式にして、もしyが0だったら何もせずにfalseを返す、正しく計算が行われたらtrueを返す、というルーチンにしました。計算の正否を関数の返値として返し、計算の結果は変数に直接返すというわけです。
 返値が欲しい時ばかりではありません。ゲームなどでは、あるルーチンを実行した時に複数の変数の値を変えたいことは良くあります。一般的なxTalkではこういう時グローバル変数を使いますが、参照渡しの方がスマートな場合があります。

 また「コピーしない」という特性を利用して、大きなデータを渡すことにも利用できます。例えば5MBのテキストをサブルーチンに渡すと、その度に5MBのコピーが作られます。メモリを余分に使いますし、メモリ移動も伴うので、数千回、数万回オーダーの呼び出しでは結構なロスになります。ところが参照渡しはアドレスを渡すだけなので、コピーに伴うロスが全く出ません。
 ただし、参照渡しで受け取った変数は、親ハンドラが使っている変数そのものです。誤って値を変更すると、親ハンドラの変数の値も変化します。これはうっかりミスを誘発しやすいです。

 xTalkで参照渡しが使えるのは多分Transcriptだけだと思いますが、どのような「作法」で使えばいいのか、私はまだちょっと迷っています。例えば親ハンドラで使っていた abc を参照渡しで使うときは変数名を abcRef とする、というような、自分なりの規則を作っておくとミスを予防出来るかも知れません。


UDI
2002.10.01
2005.01.10

inserted by FC2 system