プロダクション環境で使用されるスクリプトには、スクリプト間の競合を回避する目的で、より高度な適用範囲の指定技術を使用する必要があります。JMPにはより高度な技術が3つ用意されています。
• Names Default To Here()関数。シンプルなスクリプトであれば、このコマンドだけで十分です。詳細については、Names Default To Hereを参照してください。
• JMPで定義済みの適用範囲。詳細については、適用範囲が指定された名前を参照してください。
• 独自のスクリプトに作成できる名前空間。詳細については、名前空間を参照してください。
プロダクションで使用するスクリプトを作成する場合、そのスクリプトを現在のユーザ環境から分離する必要があります。そうでなければ、スクリプト内で使用している変数が、ユーザや別のスクリプトによって使用される他の変数の影響を受ける可能性があります。分離するためには、名前をローカル環境で使用します。それには、次のステートメントを使って実行モードを設定します。
Names Default To Here( 1 );
Names Default To Hereモードがオンになっているスクリプトの中の非修飾の名前は、そのスクリプトだけに関連付けられます。ただし、名前はスクリプトが存続する限り、または、そのスクリプトによって作成されたオブジェクトやそのスクリプトを保持しているオブジェクトがアクティブである限り、存続します。特別な理由がない限り、プロダクション環境で使用するすべてのスクリプトは、Names Default To Here(1)で開始することをお勧めします。スクリプトがこのモードで非修飾の名前を使用する場合、名前はローカルの名前空間内で解決されます。
グローバル変数を参照するには、名前の適用範囲を明確にグローバル変数として指定します(たとえば::global_name)。データテーブル内の列を参照するには、名前の適用範囲を明確にデータテーブル列として指定します(たとえば:column_name)。
注: Names Default To Here( 1 )は、特定のスクリプトのモードを定義します。グローバルな定義ではありません。あるスクリプトでこのモードを有効にし、別のスクリプトでは無効にすることができます。デフォルトではオフに設定されています。
JMP 8以前のバージョンでは、スクリプト同士を分離する唯一の方法が、他のスクリプトで使用されていないような長い名前を使用することでした。Names Default To Here(1)を使用すると、この方法が必要でなくなります。
簡単なスクリプトを作成するだけなら、Names Default To Here(1)で十分です。
Local()は、スクリプト内の特定のコンテキストにだけローカルな適用範囲を作成し、相互に作用する関数のある長いスクリプトを含めることはできません。一方、Names Default To Here(1)は、スクリプト全体に対してローカルな適用範囲を作成できます。Local()では、ローカルブロックにローカルな変数をリストします。明示的にリストされていないものは、そのブロックに対してローカルにはなりません。
Local Here()はNames Default to Here(1)をもつ名前空間ブロックを提供します。複数のスクリプトが同じルート名前空間から実行された場合(たとえば、スクリプトが同じ名前の変数を持つ2つのボタンスクリプトを実行する場合、または含まれているスクリプトがメインスクリプトから実行された場合など)、Local Here()を使用して名前の競合を防ぎます。
ローカルブロックには寿命があるのでLocal()は常に機能するとは限りませんが、Local Here()は呼び出し全体にわたって維持されます。
ここでは、メインスクリプトからインクルードされたスクリプトを実行する例を示します。それぞれのスクリプトはxとyの変数に異なる値を設定します。インクルードされるスクリプトの変数は「Local Here」名前空間にあります。
Main.jsl:
Names Default To Here( 1 );
x = 5;
y = 0;
Print( "Main, Before: x=" || Char( x ) || ", y=" || Char( y ) );
Include( "Inc1.jsl" );
Print( "Main, After: x=" || Char( x ) || ", y=" || Char( y ) );
Inc1.jsl:
Names Default To Here( 1 );
Local Here( // 変数はこのスクリプトのローカル
x = 100;
y = 100;
Print( "Inc1: x=" || Char( x ) || ", y=" || Char( y ) );
);
Print( "Inc1 outside: x=" || Char( x ) || ", y=" || Char( y ) );
この式は、次の値を戻します。
"Main, Before: x=5, y=0" // Inc1.jslを実行する前に、Main.jslで定義
"Inc1: x=100, y=100" // Inc1.jslで定義
"Inc1 outside: x=5, y=0" // Inc1.jslから、Main.jslを参照
"Main, After: x=5, y=0" // Inc1.jslの実行後、Main.jslから
inc1.jslの変数xと変数yは「Local Here」名前空間にあるために、変化しないことに注意してください。
Names Default To Here()関数は、非修飾の名前付き変数参照の解決方法を決定します。here:var_nameを使って明示的に変数のスコープを指定すれば、Names Default To Here()のオン/オフに関わらず常に適用範囲で動作します。hereその他のスコープの詳細については、適用範囲が指定された名前を参照してください。
Names Default To Hereモードを有効にすると、Hereというスコープが実行スクリプトに関連付けられます。Hereスコープには、作成された非修飾の名前付き変数のうち、割り当ての対象(L-value)であるものすべてが含まれます。JMP 8以前のバージョンでは、これらの変数は通常、グローバルスコープに置かれていました。Hereスコープを使うと、複数の実行スクリプト内の変数がお互いに分離され、名前の競合が回避されるので、変数名の管理やスクリプト作成が簡単になります。Globalスコープを使えば名前を共有できます。
このスクリプト例を一度に1行ずつ実行し、Names Default To Here()関数が変数名の解決にどのような変化をもたらすかを見てみましょう。
a = 1;
Names Default To Here( 1 );
a = 5;
Show( global:a, a, here:a );
global:a = 1;
a = 5;
here:a = 5;
1. 1行目を実行し、名前がa、値が1のグローバル変数を作成します。
2. 2行目を実行し、Names Default To Hereモードをオンにします。
3. 3行目を実行し、名前がa、値が5のローカル空間を作成します。この行は、グローバル変数aに割り当てられた値を変更しません。
4. 4行目を実行し、範囲指定された変数と範囲指定されていない変数がそれぞれどのように解決されるのかを見ます。
非修飾のaはhere:aと認識されます。Names Default To Here()がオンでない場合、aはaという名前のグローバル変数と認識されます。
ただし、Show()関数内でglobal:aの代わりに::aを使用した場合、出力は若干異なります。
Show(::a, a, here:a);
a = 1;
a = 5;
here:a = 5;
ここでは、次のような定義の2つのスクリプトがあり、どちらもNames Default To Here()がオフ(デフォルト設定)になっています。
注: この例では、2つのスクリプトのスクリプトウィンドウが別々でなければなりません。
a = 1; // スクリプト1
Show( a );
a = 3; // スクリプト2
Show( a );
1. スクリプト1を実行します。結果は次のとおりです。
a = 1
2. スクリプト2を実行します。結果は次のとおりです。
a = 3
3. スクリプト1のshow(a);行のみを実行します。結果は次のとおりです。
a = 3
変数aはグローバルで、スクリプト2によって最後に変更されたため、ログにはa = 3と表示されます。これは、JMP 9以降ではデフォルトの動作ですが、JMP 8以前のバージョンでは唯一可能な動作でした。
4. では、両スクリプトとも、Names Default To Here()をオンにしてみましょう。
Names Default To Here(1);
注: Names Default To Here()は、特定のスクリプトに対してローカルです。グローバル設定ではありません。
5. スクリプト1を実行します。結果は次のとおりです。
a = 1
6. スクリプト2を実行します。結果は次のとおりです。
a = 3
7. スクリプト1のShow( a ); 行のみを実行します。結果は次のとおりです。
a = 1
変数aのコピーが各スクリプトに保持されるため、ログにはa = 1と表示されます。
注: この関数を使用する際の問題は、通常、修飾名と非修飾名のグローバル変数への参照が混合することによって起こります。名前の適用範囲を常に明示的に指定することによって、意図しない変数への参照を防ぐことができます。