Scripting Guide > Programming Methods > Advanced Scoping and Namespaces
Publication date: 07/08/2024

Advanced Scoping and Namespaces

Scripts that are used in production environments need to use more advanced scoping techniques to avoid collisions between scripts. JMP provides three progressively more advanced techniques:

The Names Default To Here() function. If you have simple scripting needs, this single command might be sufficient. See Names Default To Here.

Scopes that are pre-defined by JMP. See Scoped Names.

Namespaces that you can create for your scripts. See JSL Namespaces.

Names Default To Here

If you write production scripts, you need to insulate the script from the current user environment. Otherwise, the variables that you use might interact with variables used by the user and by other scripts. The way to do this is to keep your names in a local environment, which you can do by setting an execution mode with the statement:

Names Default To Here( 1 );

Unqualified names in a script with the Names Default To Here mode turned on are private to that script. However, the names persist as long as the script persists, or as long as objects created by or holding the script are still active. It is recommend that all production scripts start with Names Default To Here(1) unless there is a specific reason not to do so. When the script uses an unqualified name in this mode, that name is resolved in the local namespace.

To refer to global variables, scope the name specifically as a global variable (for example, ::global_name). To refer to columns in a data table, scope with name specifically as a data table column (for example, :column_name).

Note: Names Default To Here( 1 ) defines a mode for a particular script. It is not a global function. One script can have this mode turned on, while another script can have it turned off. The default setting is off.

In JMP 8 and earlier, the only method to the insulate scripts was to use lengthy names that were less likely to collide with names in other scripts. Using Names Default To Here(1) makes this technique unnecessary.

If you have simple scripting needs, Names Default To Here(1) might be sufficient.

Local()

Local() creates local scopes only in specific contexts within a script and cannot enclose a longer script with interacting functions, while Names Default To Here(1) creates a local scope for an entire script. In Local(), you list the variables that are local to the local block. Anything not explicitly listed is not local to that block.

Local Here()

Local Here() provides a namespace block with Names Default to Here(1). Use Local Here() to prevent name collisions when multiple scripts are executed from the same root namespace (for example, when a script executes two button scripts that have the same variables or an included script is run from the main script).

Local() does not always work due to the lifetime of the local block, but Local Here() is persistent across the call.

Here’s an example that runs an included script from a main script. The scripts define x and y variables as different values. Variables in the included script are in the Local Here namespace.

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( // variables are local to this script
	x = 100;
	y = 100;
 
Print( "Inc1: x=" || Char( x ) || ", y=" || Char( y ) );
);
Print( "Inc1 outside: x=" || Char( x ) || ", y=" || Char( y ) );

Return:

"Main, Before: x=5, y=0" // defined in Main.jsl, before running Inc1.jsl

"Inc1: x=100, y=100" // defined in Inc1.jsl

"Inc1 outside: x=5, y=0" // from Inc1.jsl, referring to Main.jsl

"Main, After: x=5, y=0" // from Main.jsl, after running Inc1.jsl

Notice that the x and y variables in inc1.jsl don’t change because they’re in the Local Here namespace.

Handling Unqualified Named Variable References

The Names Default To Here() function determines how unqualified named variable references are resolved. Explicitly scoping a variable using here:var_name always works, whether Names Default To Here() is on or off. See Scoped Names for more information about here and other scopes.

Enabling the Names Default To Here mode associates a scope called Here with an executing script. The Here scope contains all of the unqualified named variables that are created when they are the target of an assignment (as an L-value). In JMP 8 and earlier, these variables normally would have been placed in the Global scope. Using a Here scope keeps variables in multiple executing scripts separate from each other, avoiding name collisions and simplifying the scripting and management of variable name collisions. You can still share information using the Global scope.

Names Default To Here and Global Variables

Run this example script one line at a time to see how the Names Default To Here() function changes the resolution of variable names.

Example Script

a = 1;
Names Default To Here( 1 );
a = 5;
Show( global:a, a, here:a );

global:a = 1;

a = 5;

here:a = 5;

1. Run the first line to create a global variable named a that holds the value 1.

2. Run the second line to turn on the Names Default To Here mode.

3. Run the third line to create a new variable named a in the local space that holds the value 5. This line does not change the value assigned to the global variable a.

4. Run the fourth line to see how scoped and unscoped variables are resolved.

The unqualified a is resolved to here:a. If Names Default To Here() were not on, a would be resolved to the global variable named a.

Note that if you use ::a instead of global:a in the Show() function, your output is a little different:

Show(::a, a, here:a);

a = 1;

a = 5;

here:a = 5;

Example of Using the Names Default To Here() Function

You have two scripts with the following definitions, andNames Default To Here() is turned off (the default condition) in both scripts.

Note: Both scripts must be in separate script windows for this example.

a = 1; // script 1
Show( a );
 
a = 3; // script 2
Show( a );

1. Run Script 1. Here is the result:

a = 1

2. Run Script 2. Here is the result:

a = 3

3. Run only the show(a); line in Script 1. Here is the result:

a = 3

The log shows a = 3 because variable a is global, and was last modified by Script 2. This is the default behavior in JMP 9 and later, and it is the only possible behavior in JMP 8 and earlier.

4. Now turn on Names Default To Here() in both scripts.

Names Default To Here(1);

Note: Names Default To Here() is local to a particular script. It is not a global setting.

5. Run Script 1. Here is the result:

a = 1

6. Run Script 2. Here is the result:

a = 3

7. Run only the Show( a ); line in Script 1. Here is the result:

a = 1

The log shows a = 1, because a copy of variable a is maintained for each script.

Note: Problems using this function are generally due to the mixing of unqualified and qualified references to global variables. Always explicitly scoping a name prevents accessing an unintended variable.

Want more information? Have questions? Get answers in the JMP User Community (community.jmp.com).