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


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

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

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

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


−−


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


 グローバル変数:

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

on mouseEnter
  put "Hello" into gAbc
end mouseEnter

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

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



 ローカル変数:

 HyperCard の変数はハンドラ内のみ有効の言わば「ハンドラ変数」でしたが、Revolution にはハンドラの外で宣言して使う「スクリプト内有効」の「ローカル変数」があります。
local sAbc

on mouseEnter
  put "Hello" into sAbc
end mouseEnter

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

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

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


 カスタムプロパティ:

 Revolution には SuperCard と同じような「カスタムプロパティ」があります。ユーザーがオブジェクトのプロパティを「作る」機能です。これを一種の変数のように使うことも出来ます。変数と違うのは、スタックを保存すれば、その値も一緒に保存されることです。ただし Revolution ではメインスタックの変更を保存出来ません。カスタムプロパティを保存したければ、そのスタックはサブスタックとして作る必用があります。



 参照渡し:

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

 通常、ハンドラや関数に値を渡すときは、その値のコピーが渡されます。
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
  put 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 )
  put tashita && hiita && kaketa && watta
end mouoseUp

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

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

 ただし、参照渡しで受け取った変数は、親ハンドラが使っている変数そのものです。誤って値を変更すると、親ハンドラの変数の値も変化します。これはうっかりミスを誘発しやすいです。上の例のように、普通に渡された変数には p で始まる変数名、参照渡しされた変数には r で始まる変数名を付けて区別すると良いでしょう。



 変数名のルール:

 LiveCode では変数名の頭に以下の1文字を付けることを推奨しています。
g- : Globa ( グローバル変数 )
s- : Script loca ( スクリプトローカル変数 )
t- : handler local ( Temporary ) ( ローカル変数/一時変数 )
p- : Parameter ( パラメータ変数 )
r- : Referenced parameter ( 参照渡しのパラメータ変数 )
k- : Constant ( 定数 )


UDI
2002.10.01
2005.01.10
2023.12.08

inserted by FC2 system