Module Declaration and Attributes
Module declaration and attributes
Module nodes create a subtree of the model tree along with a
separate namespace for all identifier declarations in that subtree. Like
Section nodes, the model contents associated with a Module node
can be stored in a separate source file. A Module node is always a
child of the main Model node, of a Section node, or of another
Module node. The attributes of Module nodes are listed in
this table.
Attribute |
Value-type |
See also page |
|---|---|---|
|
string |
|
|
|
|
|
identifier |
|
|
identifier-list |
|
|
identifier-list |
|
|
quantity::unit-list |
|
|
comment string |
The SourceFile attribute
Like with ordinary Section nodes, the contents of a Module node
can also be stored in a separate source file, dynamically linked into a
Module node in your model through the use of the SourceFile
attribute.
Modules and namespaces
The distinguishing feature of modules is that each module is supplied with a separate namespace. This means that all identifiers, procedures and functions declared within a module are, without using the module prefix, only visible within that module. In addition, within a module it is possible to redeclare identifier names that have already been declared outside the module.
Nested modules
Modules in an AIMMS model can be nested. This implies that with each
AIMMS model containing one or more Module nodes, one can associate a
corresponding tree of nested namespaces. This tree of namespaces starts
with the global namespace of the Model node as the root node. As a
consequence, you can associate a path of namespaces with every
identifier, procedure or function declaration in the model tree. This
path of namespaces starts with the global namespace down to the
namespace associated with the module in which the declaration is
contained.
Scoping rules
When AIMMS encounters an identifier reference during the compilation of a procedure or function body or in one of the attributes of an identifier declaration, AIMMS will search for a declaration of the identifier at hand in the following order.
If the referenced identifier is declared in the namespace associated with the
Module(orModel) in which the procedure, function or identifier is contained, AIMMS will use that particular declaration.If the referenced identifier cannot be found, AIMMS will repeatedly search the next higher namespace until a declaration for the identifier is found.
Consequences
As a result of these scoping rules, whenever the corresponding identifier name is referenced within a module, AIMMS has will always to refer to the identifier declaration within the same module rather than to a possibly contradicting declaration for an identifier with the same name anywhere higher up, or sideways, in the model tree. This feature enables multiple developers to work truly independently on different modules used within a model.
Example
Consider the following model with two (nested) modules, called
Module1 and Module2.
The following can be concluded by applying the scoping rules listed above.
The reference to
ShortestDistancein the procedureComputeShortestDistancein the moduleModule1refers to the declarationShortestDistancewithin that module, and not to the declarationShortestDistancein the main model.The reference to
Distancein the procedureComputeShortestDistancein the moduleModule1refers to the declarationDistance(i,j)in the main model, and not to the scalar declarationDistancewithin the nested moduleModule2.The reference to
ShortestDistancein the moduleModule2refers to the declarationShortestDistancewithin the moduleModule1, and not to the declarationShortestDistancein the main model.The parameter
Distancein the moduleModule2does not conflict with the declaration ofDistance(i,j)in the main model, because the former is only visible within the scope of the moduleModule2.
Accessing protected identifiers
The separate namespace of every module actively prevents identifiers
within a module from being “seen” outside the module. For this reason,
identifiers declared within a module are also referred to as protected
identifiers. AIMMS, however, still allows you to reference protected
identifiers anywhere else in your model through the use of the
namespace resolution operator ::. In combination with a
module-specific prefix, the :: operator accurately lets you indicate
that you are referring to a protected identifier declared in the
particular module associated with the prefix.
The Prefix attribute
With the mandatory Prefix attribute of a Module node, you must
specify a module-specific prefix to be used in conjunction with the
:: operator. The value of the Prefix attribute should be a
unique name within the namespace of the surrounding module (or main
model), and will subsequently be added to this namespace. In conjunction
with the :: operator the prefix unambiguously identifies the
namespace from which a particular identifier should be taken.
The :: namespace resolution operator
With the namespace resolution operator :: you instruct AIMMS to
look for the identifier directly following the :: operator within
the module associated with the prefix in front it. The :: operator
may be optionally surrounded with spaces. By stacked use of the ::
operator you can indicate that you want to refer to an identifier
declared in a nested module. Each next prefix should refer to the
Prefix attribute of the module declared directly within the module
associated with the previous prefix.
Using global identifiers in ModuleS
If you want to refer to an identifier in the main model, that is also
declared elsewhere along the path from the current module to the main
model, you can use the :: operator without a prefix. This
indicates to AIMMS that you are interested in an identifier declared in
the global namespace associated with the main model.
Examples
Consider the model outlined in the example above.
Within the main model, a reference
m1::ShortestDistancewould refer to the parameterShortestDistancedeclared within the moduleModule1, and not to the parameterShortestDistancedeclared in the main model itself.Within the main model, a reference
m1::m2::Distancewould refer to the parameterDistancedeclared in the moduleModule2nested within the moduleModule1.Within the module
Module1, a reference to::ShortestDistancewould refer to the parameterShortestDistancedeclared in the main model, and not to the parameterShortestDistancedeclared inModule1.Within the module
Module2, a reference to::Distancewould refer to the parameterDistancedeclared in the main model, and not to the parameterDistancedeclared inModule2.
The following model outline, which is a variation of the model outline
of the previous example, further illustrates the consequences of the use
of the :: operator.
The Public attribute
Through the Public attribute you can indicate that a set of
identifiers declared within the module is public. These identifiers can
then be referenced without the :: operator within the importing
module (or main model). The value of the Public attribute must be a
constant set expression. You might consider the identifiers specified in
the Public attribute as the public interface of a module. As a
result, AIMMS will effectively add the names of these identifiers to the
namespace of the importing module, as if they were declared within the
importing module itself.
Example
Consider the model outline of the first example, and assume that the
declaration of module Module2 is augmented as follows.
Module Module2 {
Prefix : m2;
Public : {
data { Distance }
}
...
Parameter Distance {
Definition : ShortestDistance;
}
...
}
As a result of the Public attribute, Distance will be added to
the namespace of Module1, and the compilation of the procedure
ComputeShortestDistance will fail because Distance will now
refer the scalar declaration in Module2 rather than to the
2-dimensional declaration in the main model. In addition, it is
possible, within the main model, to refer to the parameter Distance
in Module2 through the expression m1::Distance, because
Distance has been effectively added to the namespace of module
Module1.
Propagation of public identifiers
When an identifier is added to the Public attribute of an imported
module, it is, as explained above, effectively added to the namespace of
the importing module. This creates the possibility to add a public
identifier of an imported module to the Public attribute of the
importing module as well. In this way you can propagate the public
character of such an identifier to the next outer namespace. For
example, by adding the identifier Distance in the example above, to
the Public attribute of the module Module1 as well, it would
also become public in the main model. Obviously, in this case, adding
Distance to the Public attribute of Module1 would cause a
name clash with the global identifier Distance(i,j).
The Protected attribute
Once you import a module into an existing AIMMS application, one or more
identifiers in the public interface of the imported module can cause
name clashes with existing identifiers in the application, like
Distance in the example of previous paragraph. When you run into
such a problem, AIMMS allows you to override the Public status of
one or more identifiers of a module through its Protected attribute.
The value of the Protected attribute must be a constant set
expression, and its contents must be a subset of the set of identifiers
specified in the Public attribute. By adding an identifier to the
Protected attribute, it is, again, only accessible outside of the
module by using the :: operator.
Public versus Protected responsibilities
The responsibilities for specifying the Public and Protected
attributes are substantially different, and result in a different
storage of the values of these attributes. This is similar to the
SouceFile-related attributes discussed earlier in this chapter. The
following rules apply.
The
Publicattribute is intended for the developer of a module to define a public interface to the module. If the module is stored in a separate.ambfile, to be imported by other AIMMS applications, the contents of thePublicattribute is stored inside the module-specific.ambfile.The
Protectedattribute is intended for the user of a module to override the public character of certain identifiers as specified by the developer of the module. As the contents of theProtectedattribute is not an integral part of the module, but may be specified differently by every user of the module, it is never stored in a module-specific.ambfile, but rather in the importing module or main model.
Unique global representation
For each identifier in an AIMMS model, there is a unique global
representation. If the identifier is contained in the global namespace
of the main model, the global representation is the identifier name
itself. If an identifier is only contained in the namespace of a
particular module, its unique representation based on the namespace
Prefix of the module and the :: operator. Thus, for the first
example of this section (without Public attributes), the unique
global representations of all identifiers are:
Distance(i,j)ShortestDistancem1::ShortestDistancem1::ComputeShortestDistancem1::m2::Distance
With the Public attribute of Module2 defined as in the previous
example, the unique global representation of the parameter Distance
in Module2 becomes m1::Distance, as it effectively causes
Distance to be contained in the namespace of Module1.
The Required Units attribute
It is recommended to declare all quantities and units at one place in the main model, and thus
not declare quantities in a module as this could lead to a model where the same quantities and units are
declared multiple times. With the Required Units attribute of a Module node,
you can specify the units that are used in the module and thus should be
present in the model that includes this module. If the required units
are SI units, then they will be added automatically to the model that includes this module.
The value of this attribute is a list of quantity::unit specifications. For example:
SI_Time_Duration::hour, SI_Length::inch. Note that this attribute is only available if the module
has the source file attribute specified.
Display and data transfer
Whenever AIMMS is requested to DISPLAY or WRITE the contents of
one or more identifiers in your model, it will use the unique global
representation discussed in the previous paragraph. Also, when you
READ data from a file, AIMMS expects all identifiers for which data
is provided in the file to be identified by their unique global
representation.