スコープ
ウィジェット参照のスコープ
ユーザインターフェース定義内に作られたウィジェットは,スクリプトコードやその他のウィジェットから容易に検索できるように名前を付けてオブジェクトレジストリに登録することができる.完全なインターフェース定義も他の定義内で,またウィジェット参照へのスコープアクセスの問題が起ったときに再利用することができる.次は,ウィジェット参照を使う場合に留意したい,設計に関連する2つの問題点である.
- デフォルトで,ウィジェット参照は単一のインターフェース定義式またはファイルによってスコープされる.すべてのウィジェット参照がすべてのScript[]ブロックと単一の定義内にあるWidgetReference[]リクエストからアクセス可能である.
- Widget["path",{…},…]を使って定義をラップすることで他のインターフェース定義がロードされた場合,最も外側のルートウィジェットのみがデフォルトで公開され,オプションName->"myName"を使ってラッピング定義内で名付けることができる.他のウィジェットもこの外部定義内から公開することが望ましい場合は,オプションExposeWidgetReferences->{"name1","name2"->"newName2",…}を使って子定義内の他のウィジェットへの名前付きのアクセスを含むことができる.
スクリプトのスコープ
Scriptブロックは,一般にインターフェース定義内で使われ,インターフェースウィジェットの状態を動的に変化させ,Wolfram言語プログラミング関数を定義し,ウィジェットからWolfram言語関数の呼出しにイベントをバインドする.これにはWolfram言語カーネルとスクリプトコードが同時に実行されている複数のインターフェース定義が含まれるので,スクリプトコードのスコープとそのカーネルコンテキスト使用についての疑問が起る.次はScriptコードブロックを開発する際に留意したい,いくつかの設計上の問題である.
- Script[]ブロックはすべて,単一のインターフェース定義式かファイルによって範囲が決められている.インターフェース定義の各インスタンスのために新たなプライベートカーネルコンテキストが作られ,すべてのScript[]ブロックがこの新たなコンテキスト内で評価される.インターフェースがライブのときにBindEventブロックとScriptブロックが連続して呼ばれても,スクリプトコードの実行中にこの同じプライベートコンテキストが設定され,インターフェース定義が最初にロードされたときに他のトップレベルのScript[]ブロックで定義された任意の関数が使用可能となる.これは,HTMLページでJavaScriptコードをロードするのと極めて似ている.この定義の各インスタンスのためのプライベートな新規のコンテキストもまた,他の定義によって上書きされる心配をせずにユーザのスクリプト内で大域変数を使用することを可能にする.
- Widget["path",{…},…]を使って他のインターフェース定義がアクセスされると,これは新たなカーネルコンテキストを受け取って内部スクリプトを実行するので,外部定義のScriptブロックはデフォルトで親すなわち包み込んでいる定義や親Scriptコードおよび関数定義を共有することもこれにアクセスすることもできない.
- Script[{},ScriptSource->"file.m"]を使って大きなスクリプトコードブロックを分割するのであっても,Scriptのこの形式は他の外部定義としての資格がないので,定義に明示的にコードを含んでいるScript[]ブロックと同じ共有カーネルコンテキストを使うことになる.
- $ContextPathは,それぞれの新たなインターフェース定義のインスタンスについてもともと{"GUIKit`","JLink`","System`"}と定義されており,Scriptの呼出しから脱出する際に外部の大域$ContextPathにリセットされる.このため,自分のスクリプトで使用するWolfram言語パッケージについては,それが何であれ明示的にNeedsを呼び出す必要がある.各ユーザインターフェースインスタンスの内部のスクリプトに関しては一意的な$ContextPathが保たれているので,GUIKit の定義もパッケージの使用を大域的$ContextPathには公開せず,複数のパッケージが同じシンボル名を使うことによるシンボルのシャドーイングの可能性を防いでいる.
- 無論,明示的なコンテキスト付けをされたシンボルや関数の呼出しを使って共有カーネルコードにアクセスすることも可能である.場合によっては,開発中やインタラクティブなノートブックで作業している場合等に,GUIKit ユーザインターフェース定義のスクリプトが共有のGlobal`コンテキスト記号や関数にアクセスできた方が望ましいだろう.しかし,こうすると,この定義の複数のインスタンスが同時にアクティブになるとこの定義が使えなくなるかもしれない.GUIRun,GUIRunModalおよびこれらと類似の関数は,ユーザインターフェースのスクリプト$ContextPathに入れる付加的なコンテキストのリストを指定するためのIncludedScriptContextsオプションをサポートしている.
- ScriptはHoldAllCompleteであるので,コードブロックは自動的には自身のコードを評価しない.ノートブックでインタラクティブにインターフェース定義を構築しているとしたら,他の式で作業をしているときにScript関数のあるものがGlobal`コンテキストに現れるのに,インターフェースがライブになってもなおランタイムでは定義とスクリプトが新たなプライベートコンテキストで定義されていることに気付くことがあるかもしれない.
以下は,GUIKit のScriptのコンテキストと$ContextPath管理の本質を示すいくつかの例題である.
以下でデフォルトの大域的$Contextと$ContextPathの状態を示す.
次では, $Contextと$ContextPathの状態を示す GUIKit 定義を実行し,ボタンをクリックするたびにこれらの値を出力する.
次に大域的$ContextPathを更新するWolfram言語パッケージをロードする.
新しい定義を実行すると,定義の$ContextPathには外部的にロードされたWolfram言語パッケージは含まれない.逆に, GUIKit 定義のScriptブロックに対して内部的であるパッケージのNeedsを呼び出しても,それは大域的$ContextPathを変更しない.
次を見ると.外部$ContextPathはパッケージをロードする GUIKit のScriptブロックには影響されていないのが分かる.
GUIKit の定義はデフォルトでそれ自身のプライベート$ContextPathと$Contextを使うので,大域的に保存されたシンボルや関数へはScriptコード内からはアクセスできない.
次で,デフォルトでユーザインターフェースには大域的に定義された記号や関数が見えないのが分かる.
GUIRunのIncludedScriptContextsオプションを使って"Global`"コンテキストをユーザインターフェースの可視的コンテキストとして含めば,Scriptブロックに外部的に定義された記号が見るようになる.