Scoping
Scoping of Widget References
Widgets created within a user interface definition can be named and registered in an object registry for easy lookup reference by script code and other widgets. Complete interface definitions can also be reused within other definitions and the issue of scoping access to widget references arises. Here are two design issues to keep in mind when working with widget references.
- By default, widget references are scoped by a single interface definition expression or file. All widget references are accessible across all Script[] blocks and WidgetReference[] requests within a single definition.
- When another interface definition is loaded using Widget["path", {...}, ...] by a wrapping definition, only the outermost root widget is exposed by default and can be named within the wrapping definition using the option Name->"myName". If it is desired that other widgets be exposed from within this external definition, you can use the option ExposeWidgetReferences->{"name1", "name2"->"newName2", ...} to include named access to other widgets inside the child definition.
Scoping of Scripts
Script blocks are typically used within interface definitions to define
Mathematica programming functions, dynamically change the state of interface widgets, and to bind events from widgets into calls to
Mathematica functions. Since this involves the
Mathematica kernel and multiple interface definitions with their own script code running at the same time, the question of script code scoping and their use of kernel contexts arises. Here are several design issues to keep in mind when developing
Script code blocks.
- All Script[] blocks are scoped by a single interface definition expression or file. A new private kernel context is created for each instance of an interface definition and all Script[] blocks are evaluated within this new context. Even when BindEvent Script blocks are subsequently called when the interface is live, this same private context is set while the script code is executing, thus also making available any functions defined by other top-level Script[] blocks defined when the interface definition was first loaded. This is quite similar to the loading of JavaScript code in HTML pages. This private new context for each instance of a definition also allows you to use global variables within your scripts without worrying about them being overwritten by other definitions.
- When another interface definition is accessed using Widget["path", {...}, ...] , it receives its own new internal kernel context to run its internal scripts in, so external definition Script blocks will not by default share or have access to the parent or wrapping definition and the parent Script code and function definitions.
- The use of Script[{}, ScriptSource->"file.m"] to break out large script code blocks will still use the same shared kernel context with Script[] blocks that explicitly contain the code in the definition, as this form of Script does not qualify as another separate external definition.
- $ContextPath is initially defined to {"GUIKit`", "JLink`", "System`"} for each new interface definition instance and is reset to the external global $ContextPath when exiting a Script call. This means that you must explicitly call Needs on any Mathematica packages that are used by our scripts. Since a unique $ContextPath is maintained for scripts inside each user interface instance, GUIKit definitions will also not expose their use of Mathematica packages to the global $ContextPath, preventing the potential symbol shadowing by multiple packages using the same symbol names.
- You can still use explicit contexted symbol and function calls to access shared kernel code. In certain cases, during development or for interactive notebook work, it may be more desirable to allow the scripts of a GUIKit user interface definition to access shared Global` contexted symbols and functions, though this may break the ability of this definition to work when multiple instances of it are active at the same time. GUIRun, GUIRunModal, and similar functions support the IncludedScriptContexts option for specifying a list of additional contexts that should be included on a user interface's scripts $ContextPath.
- Script is HoldAllComplete so code blocks will not automatically evaluate their code. If you are interactively building up an interface definition in a notebook, you may notice some of the Script functions showing up in the Global` context while working with the expressions, but at runtime the definition and scripts will still get defined within a new private context when the interface is live.
Here are a few examples that demonstrate the nature of
GUIKit's
Script context and
$ContextPath management.
Here you can show the default global
$Context and
$ContextPath state.
| Out[2]= |  |
Here you run a
GUIKit definition which shows its
$Context and
$ContextPath state and prints these values each time you click its button.
| Out[3]= |  |
Now load a
Mathematica package which updates the global
$ContextPath.
| Out[5]= |  |
Notice that if you run a new definition, the definition's
$ContextPath does not include the externally loaded
Mathematica package, and conversely, if you call
Needs on a package internal to the
Script block of the
GUIKit definition, it does not change the global
$ContextPath.
| Out[6]= |  |
Here you see that the external
$ContextPath is unaffected by the
GUIKit's
Script block loading of packages.
| Out[7]= |  |
Because
GUIKit definitions use their own private
$ContextPath and
$Context by default, access to globally stored symbols or functions are not visible within
Script code.
Here you see that the user interface does not see globally defined symbols and functions by default.
| Out[10]= |  |
If you were instead to use the
IncludedScriptContexts option of
GUIRun to include the
"Global`" context as a visible context for the user interface, then the
Script blocks would see these externally defined symbols.
| Out[11]= |  |