How Modules Work

The way modules work in the Wolfram Language is basically very simple. Every time any module is used, a new symbol is created to represent each of its local variables. The new symbol is given a unique name which cannot conflict with any other names. The name is formed by taking the name you specify for the local variable, followed by $, with a unique "serial number" appended.

The serial number is found from the value of the global variable (RefLink[$ModuleNumber, paclet:ref/$ModuleNumber]). This variable counts the total number of times any (RefLink[Module, paclet:ref/Module]) of any form has been used.

The basic principle of modules in the Wolfram Language.

This shows the symbol generated for t within the module:

Module[{t},Print[t]]

The symbols are different every time any module is used:

Module[{t,u},Print[t];Print[u]]

For most purposes, you will never have to deal directly with the actual symbols generated inside modules. However, if for example you start up a dialog while a module is being executed, then you will see these symbols. The same is true whenever you use functions like (RefLink[Trace, paclet:ref/Trace]) to watch the evaluation of modules.

You see the symbols that are generated inside modules when you use (RefLink[Trace, paclet:ref/Trace]):

Trace[Module[{t},t=3]]

This starts a dialog inside a module:

Module[{t},t=6;Dialog[]]

Inside the dialog, you see the symbols generated for local variables such as t:

Stack[_]

You can work with these symbols as you would with any other symbols:

t$4+1

This returns from the dialog:

Return[t$4^2]

Under some circumstances, it is convenient explicitly to return symbols that are generated inside modules.

You can explicitly return symbols that are generated inside modules:

Module[{t},t]

You can treat these symbols as you would any others:

%^2+1

Generating new symbols with unique names.

The function (RefLink[Unique, paclet:ref/Unique]) allows you to generate new symbols in the same way as (RefLink[Module, paclet:ref/Module]) does. Each time you call (RefLink[Unique, paclet:ref/Unique]), (RefLink[$ModuleNumber, paclet:ref/$ModuleNumber]) is incremented, so that the names of new symbols are guaranteed to be unique.

This generates a unique new symbol whose name starts with x:

Unique[x]

Each time you call (RefLink[Unique, paclet:ref/Unique]), you get a symbol with a larger serial number:

{Unique[x],Unique[x],Unique[x]}

If you call (RefLink[Unique, paclet:ref/Unique]) with a list of names, you get the same serial number for each of the symbols:

Unique[{x,xa,xb}]

You can use the standard Wolfram Language ?name mechanism to get information on symbols that were generated inside modules or by the function (RefLink[Unique, paclet:ref/Unique]).

Executing this module generates the symbol q$nnn:

Module[{q},q^2+1]

You can see the generated symbol here:

?q*

Symbols generated by (RefLink[Module, paclet:ref/Module]) behave in exactly the same way as other symbols for the purposes of evaluation. However, these symbols carry the attribute (RefLink[Temporary, paclet:ref/Temporary]), which specifies that they should be removed completely from the system when they are no longer used. Thus most symbols that are generated inside modules are removed when the execution of those modules is finished. The symbols survive only if they are explicitly returned.

This shows a new q variable generated inside a module:

Module[{q},Print[q]]

The new variable is removed when the execution of the module is finished, so it does not show up here:

?q*

You should realize that the use of names such as x$nnn for generated symbols is purely a convention. You can in principle give any symbol a name of this form. But if you do, the symbol may collide with one that is produced by (RefLink[Module, paclet:ref/Module]).

An important point to note is that symbols generated by (RefLink[Module, paclet:ref/Module]) are in general unique only within a particular Wolfram Language session. The variable (RefLink[$ModuleNumber, paclet:ref/$ModuleNumber]) which determines the serial numbers for these symbols is always reset at the beginning of each session.

This means in particular that if you save expressions containing generated symbols in a file, and then read them into another session, there is no guarantee that conflicts will not occur.

One way to avoid such conflicts is explicitly to set (RefLink[$ModuleNumber, paclet:ref/$ModuleNumber]) differently at the beginning of each session. In particular, if you set (RefLink[$ModuleNumber, paclet:ref/$ModuleNumber])=10^10 (RefLink[$SessionID, paclet:ref/$SessionID]), you should avoid any conflicts. The global variable (RefLink[$SessionID, paclet:ref/$SessionID]) should give a unique number which characterizes a particular Wolfram Language session on a particular computer. The value of this variable is determined from such quantities as the absolute date and time, the ID of your computer, and, if appropriate, the ID of the particular Wolfram System process.

Variables to be used in determining serial numbers for generated symbols.

Having generated appropriate symbols to represent the local variables you have specified, (RefLink[Module, paclet:ref/Module])[vars,body] then has to evaluate body using these symbols. The first step is to take the actual expression body as it appears inside the module, and effectively to use (RefLink[With, paclet:ref/With]) to replace all occurrences of each local variable name with the appropriate generated symbol. After this is done, (RefLink[Module, paclet:ref/Module]) actually performs the evaluation of the resulting expression.

An important point to note is that (RefLink[Module, paclet:ref/Module])[vars,body] inserts generated symbols only into the actual expression body. It does not, for example, insert such symbols into code that is called from body, but does not explicitly appear in body.

"Blocks and Local Values" discusses how you can use (RefLink[Block, paclet:ref/Block]) to set up "local values" which work in a different way.

Since x does not appear explicitly in the body of the module, the local value is not used:

tmp=x^2+1;Module[{x=4},tmp]

Most of the time, you will probably set up modules by giving explicit Wolfram Language input of the form (RefLink[Module, paclet:ref/Module])[vars,body]. Since the function (RefLink[Module, paclet:ref/Module]) has the attribute (RefLink[HoldAll, paclet:ref/HoldAll]), the form of body will usually be kept unevaluated until the module is executed.

It is, however, possible to build modules dynamically in the Wolfram Language. The generation of new symbols, and their insertion into body are always done only when a module is actually executed, not when the module is first given as Wolfram Language input.

This evaluates the body of the module immediately, making x appear explicitly:

tmp=x^2+1;Module[{x=4},Evaluate[tmp]]