Variables have an attribute called scope, which determines where in MAXScript code a variable can be accessed.
MAXScript has two kinds of variable scope, global and local.
Global variables are visible in all running MAXScript code and hold their values until you exit 3ds Max.
Local variables are directly visible to code only in the lexical scope currently in effect, and hold their values only as long as the current scope is active. Once a scope is no longer active, you can no longer access the contents of a variable local to that scope. This is similar to how most modern programming languages implement variables. The conditions under which MAXScript creates a new scope are described further on this page.
MAXScript provides language constructs used to explicitly declare and initialize both global and local variables.
The syntax for variable declaration, <variable_decls> , is as follows:
As mentioned above, local variables hold their values as long as that scope is active. In nested scopes, this is usually a very short period - it starts when a function or loop or block expression runs and ends when it exits.
Each time the scope is entered at runtime, a new set of locals is created and then retired when the scope is exited.
It is a good practice to always declare variables explicitly. See further on this page for some good reasons.
Since 3ds Max 8, MAXScript provides a way to explicitly access a variable name as global. If the variable exists in the global pool of variables, it will be used. If the variable name does not exist in the global scope, it will be created as explicitly global.
The syntax is double-colon '::' and is described in this topic.
In certain situations, the top-level scope can remains active for extended periods and so the locals declared at that top-level hold their values for that extended period.
In particular, top-level locals declared in scripted rollouts, utilities, plug-ins, script controllers and Macro Scripts hold their values for as long as the rollout, utility, plug-in, or Macro Script exists.
Typically, they remain in existence until you redefine them, so for example when you define a Macro Script and run it for the first time, the top-level scope is created and remains active over any number of subsequent executions unless you redefine the Macro Script. At this point, the existing top-level scope is retired and a fresh one (along with its top-level locals) is created.
This lets you use top-level locals in these constructs as a kind of private global; the values they hold remain in place over many executions, but only code in that construct can see the variable and so it does not conflict with actual global variables.
Note that in scripted plug-ins, a separate copy of the top-level local scope is created for each instance of the plugin and this scope remains active while that instance remains in existence up until the end of the current 3ds Max session.
If you do not explicitly declare a variable, and the variable name does not exist at a higher scope, MAXScript will create the variable the first time you use it and initialize it to hold the special value undefined . You are not required to explicitly declare a variable, or initialize its value, before you can use it. Variable names not explicitly declared by one of the previous statements are called implicitly declared variables. The scope of implicitly declared variables is the MAXScript scope context currently in effect when the variable is first used. The initial MAXScript scope context is global, and new scope contexts are opened for the following:
Top-level open parentheses in a script file or in the Listener
Start of a utility, rollout, right-click menu, Macro Script, or tool definition
Start of a rollout, utility, right-click menu, Macro Script, or tool event handler
Within these new scopes, newly referenced variables will be implicitly declared as local variables.
Scope contexts are nested, with the scope of a variable explicitly or implicitly declared at one scope context level extending to all scope contexts below that level.
Take for example the following script:
In the above script, variable a is first used in the global scope context, and its scope includes scope contexts global, level 1, and level 2.
Variable b is first used in scope context level 1, so it is implicitly declared as a local variable and its scope includes scope contexts level 1 and 2.
Variables i and j are first used in scope context level 2, and their scope is only scope context level 2.
The scope of variable k varies depending on whether this script has been run before.
The first time the script is run, variable k is first defined at line 5, and its scope is scope context level 2.
In line 11, variable k is used again. Because the variable k defined at line 5 is no longer in scope, a new variable k is defined whose scope is global.
The second time you run the script, at line 5 MAXScript detects variable k already exists and uses it.
So the first time you run the script line 11 will print undefined , and the second time you run the script line 11 will print the last value calculated at line 5!
When you explicitly declare a local variable, you can reuse the same name as a variable at a higher scope context level.
If you do this, the newly declared local variable hides the outer variables with the same name.
Any reference to that variable name later in the local variable's scope refers to the new local variable.
At the end of the local variable's scope, the next outer variable becomes visible again.
This visibility scheme is called lexical scoping. An example of lexical scoping is shown in the following script.
This might seem a strange way of over-using a single variable name, but in large programs, these scoping rules can be useful.
For example, you may add a new user-interface item and its handlers to a utility script. By explicitly declaring the variables used in the handlers as local, you ensure these variables are independent of any preexisting variables with the same names in the remainder of the script.
When writing scripts, it is good programming practice to explicitly declare your local and global variables.
Implicit declaration is provided as a short-hand, typically used when working in the Listener interactively or developing short scripts.
When developing extended scripts, explicitly declaring variables can reduce errors and improve readability of the code.
It is also recommend that you declare as local all variables unless you really want them to be global variables. There are several reasons for this practice:
All the variable names used in the block or function will be together, which makes it easier to find the variable names and helps prevent using incorrect names in the script.
If more than one script is script is executed at the same time (for example, you are running a scripted utility and have a scripted controller in the scene) and both scripts use the same global variable name, the two scripts can interfere with one another. This can cause apparently random failures of one or both scripts.
You are sure you are using the correct variable in the event that a variable with the same name has already been declared at a higher scope, and you won't inadvertently change the higher-level variable's value.
Values of variables explicitly defined as local are displayed in error call stack trace-backs.
In 3ds Max R2.5, if a 3ds Max class, a MAXScript method, or a MAXScript read-only global variable has the same name as an implicitly declared local variable, a MAXScript runtime error will be generated if an assignment to that variable name occurs. Since the variable name already existed with a global scope, an implicitly declared local variable was not created. Since one or more new 3ds Max classes will be created by any third party plug-ins the user has loaded, you were not be able to tell ahead of time if a variable name was a global variable name. In 3ds Max R3, if the MAXScript compiler detects that the first reference to such a variable is an assignment, it will implicitly declare a local variable, rather than leaving it as a reference to a read-only system global. For example, executing the following expression in 3ds Max R2.5 would result in a value of Box , since Box is a 3ds Max object class. In 3DS R3, MAXScript detects that the first use of variable box is an assignment and creates an implicitly declared local variable box . The result of this expression in 3ds Max R3 is the value undefined .
In the following script, an error was introduced by using undefined variable k in line 7. In the output, the error call stack trace-back shows the value for variable b in function afunc and in the block-expression calling afunc .
If the same script is run with lines 3 and 12 removed, the following output is generated. Because function afunc and the block-expression are in different MAXScript scope contexts, variable b is implicitly declared as local in each and contain different values. However, because they were implicitly defined, they are not included in the error call stack trace-back.