Recall the following example from our discussion on Organizing Content:
within ModelicaByExample.PackageExamples;
package NestedPackages
"An example of how packages can be used to organize things"
package Types
type Rabbits = Real(quantity="Rabbits", min=0);
type Wolves = Real(quantity="Wolves", min=0);
type RabbitReproduction = Real(quantity="Rabbit Reproduction", min=0);
type RabbitFatalities = Real(quantity="Rabbit Fatalities", min=0);
type WolfReproduction = Real(quantity="Wolf Reproduction", min=0);
type WolfFatalities = Real(quantity="Wolf Fatalities", min=0);
end Types;
model LotkaVolterra "Lotka-Volterra with types"
parameter Types.RabbitReproduction alpha=0.1;
parameter Types.RabbitFatalities beta=0.02;
parameter Types.WolfReproduction gamma=0.4;
parameter Types.WolfFatalities delta=0.02;
parameter Types.Rabbits x0=10;
parameter Types.Wolves y0=10;
Types.Rabbits x(start=x0);
Types.Wolves y(start=y0);
equation
der(x) = x*(alpha-beta*y);
der(y) = -y*(gamma-delta*x);
end LotkaVolterra;
end NestedPackages;
When we discussed Referencing Package Contents, the example that was
presented used fully qualified names for all the types it referenced.
But the example above doesn’t. We see, from the LotkaVolterra
model that the Wolves
type is referenced as:
parameter Types.Wolves y0=10;
And not as:
parameter ModelicaByExample.PackageExamples.NestedPackages.Types.Wolves y0=10;
In other words, we didn’t use the fully qualified name. But the
LotkaVolterra
model compiles just fine. So how is it that the
Modelica compiler knows which definition of Wolves
to use?
The answer involves “name lookup” in Modelica. Name lookup in
Modelica involves searching for the named definition. Type names in
Modelica are generally qualified (although not necessarily fully
qualified) names. This means they may contain a .
in them,
e.g., Modelica.SIunits.Voltage
. In order to locate the matching
definition associated with a name, the Modelica compiler starts by
looking for the first name in the qualified name, e.g.,
Modelica
. It searches for a matching definition in the following order:
Look for a matching name among builtin types
Look in the current definition for a nested definition with a matching name (include inherited definitions)
Look in the current definition for an imported definition with a matching name (do not include inherited imports)
Look in the parent package of the current definition for a nested definition with a matching name (including inherited definitions)
Look in the parent package for an imported definition with a matching name (not including inherited imports)
Look in each successive parent (using the same approach) until either:
- The parent package has the
encapsulated
qualifier, in which case the search terminates.- There are no more parent packages, in which case you search for a match among root level packages.
If the given name cannot be found after searching all these locations,
then the search fails and the type cannot be resolved. If the search
succeeds, then we’ve located the definition of the first name in
the qualified name. If the name is not qualified (i.e., it does not
have a .
in the name), then we are done. However, if it does have
other components in the name, these must be nested definitions
contained within the definition returned by the search. If nested
definitions cannot be found for all remaining components in a
qualified name, then the search fails and the type cannot be resolved.
At first, this might sound very complicated. However, most of the time these rules are not very important. The reason is that, as we discussed previously, most graphical Modelica environments will use fully qualified names. Most type names in Modelica code will either reference local definitions or will be specified with fully qualified names.
Duplicate Names
You should always avoid having nested packages with the same name as a top-level package. The reason this is a problem is that the lookup rules search up through the package hierarchy. As a result, they will find the nested definition before the root level one. This means that lookup of fully qualified names (ones that are referenced relative to the root of the package tree) will fail because they will find the nested definition first.