Packages

Package as Specialized Class

The package concept is a specialized class (), using the keyword package.

Motivation and Usage of Packages

[Packages in Modelica may contain definitions of constants and classes including all kinds of specialized classes, functions, and subpackages. By the term subpackage we mean that the package is declared inside another package, no inheritance relationship is implied. Parameters and variables cannot be declared in a package. The definitions in a package should typically be related in some way, which is the main reason they are placed in a particular package. Packages are useful for a number of reasons:

  • Definitions that are related to some particular topic are typically grouped into a package. This makes those definitions easier to find and the code more understandable.
  • Packages provide encapsulation and coarse-grained structuring that reduces the complexity of large systems. An important example is the use of packages for construction of (hierarchical) class libraries.
  • Name conflicts between definitions in different packages are eliminated since the package name is implicitly prefixed to names of definitions declared in a package.
  • Information hiding and encapsulation can be supported to some extent by declaring protected classes, types, and other definitions that are available only inside the package and therefore inaccessible to outside code.
  • Modelica defines a method for locating a package by providing a standard mapping of package names to storage places, typically file or directory locations in the file system.

]

Importing Definitions from a Package

The import-clause makes public classes and other public definitions declared in some package available for use by shorter names in a class or a package. It is the only way of referring to definitions declared in some other package for use inside an encapsulated package or class.

[Import-clauses in a package or class fill the following two needs:

  • Making definitions from other packages available for use (by shorter names) in a package or class.
  • Explicit declaration of usage dependences on other packages.

]

An import-clause can occur in one of the following five syntactic forms:

import packagename; (qualified import)

import [packagename.]definitionname; (single definition import)

import [packagename.]{def1,def2,…defN}; (multiple definition import)

import packagename.*; (unqualified import)

import shortpackagename = packagename; (renaming import)

import shortpackagename = [packagename.]definitionname; (renaming single def. import)

Here packagename is the fully qualified name of the imported package including possible dot notation and definitionname is the name of an element in a package. The multiple definition import is equivalent to multiple single definition imports with corresponding packagename and definition names.

Lookup of Imported Names

This section only defines how the imported name is looked up in the import clause. For lookup in general – including how import clauses are used, see .

Lookup of the name of an imported package or class, e.g. A.B.C in the clauses import A.B.C; import D=A.B.C; import A.B.C.*, deviates from the normal lexical lookup by starting the lexical lookup of the first part of the name at the top-level.

Qualified import clauses may only refer to packages or elements of packages, i.e., in import A.B.C; or import D=A.B.C;, A.B must be a package. Unqualified import clauses may only import from packages, i.e., in import A.B.*;, A.B must be a package. [Note: in import A; the class A can be any class which is an element of the unnamed top-level package]

[For example, if the package ComplexNumbers would have been declared as a subpackage inside the package Modelica.Math, its fully qualified name would be Modelica.Math.ComplexNumbers. Definitionname is the simple name without dot notation of a single definition that is imported. A shortpackagename is a simple name without dot notation that can be used to refer to the package after import instead of the presumably much longer packagename.

The forms of import are exemplified below assuming that we want to access the addition operation of the hypothetical package Modelica.Math.ComplexNumbers:

import Modelica.Math.ComplexNumbers; // Accessed by ComplexNumbers.Add
import Modelica.Math.ComplexNumbers.Add; // Accessed by Add
import Modelica.Math.ComplexNumbers.{Add,Sub}; // Accessed by Add and Sub
import Modelica.Math.ComplexNumbers.*; // Accessed by Add
import Co = Modelica.Math.ComplexNumbers; // Accessed by Co.Add

]

Summary of Rules for Import Clauses

The following rules apply to import-clauses:

  • Import-clauses are not inherited.
  • Import-clauses are not named elements of a class or package. This means that import-clauses cannot be changed by modifiers or redeclarations.
  • The order of import-clauses does not matter.
  • One can only import from packages, not from other kinds of classes. Both packages and classes can be imported into i.e., they may contain import-clauses.
  • An imported package or definition should always be referred to by its fully qualified name in the import-clause.
  • Multiple qualified import-clauses may not have the same import name.

Mapping Package/Class Structures to a Hierarchical File System

Packages/classes may be represented in the hierarchical structure of the operating system [the file system]. For classes with version information see also . The nature of such an external entity falls into one of the following two groups:

  • Directory in the file system.
  • File in the file system.

Each Modelica file in the file-system is stored in UTF-8 format (defined by The Unicode Consortium; http://www.unicode.org) and may start with the UTF-8 encoded byte order mark (0xef 0xbb 0xbf); this is treated as white-space in the grammar. [Tools may also store classes in data-base systems, but that is not standardized.]

Mapping a Package/Class Hierarchy into a Directory Hierarchy (Structured Entity)

A directory shall contain a node, the file package.mo. The node shall contain a stored-definition that defines a class [A] with a name matching the name of the structured entity. [The node typically contains documentation and graphical information for a package, but may also contain additional elements of the class A.]

A directory may also contain one or more sub-entities (directories or files). The sub-entities are mapped as elements of the class defined by their enclosing structured entity. [For example, if directory A contains the three files package.mo, B.mo and C.mo the classes defined are A, A.B, and A.C.] Two sub-entities shall not define classes with identical names [for example, a directory shall not contain both the sub-directory A and the file A.mo].

In order to preserve the order of sub-entities it is advisable to create a file package.order where each line contains the name of one class or constant. If a package.order is present when reading a structured entity the classes and constants are added in this order; if the contents does not exactly match the classes and constants in the package, the resulting order is tool specific and a warning may be given. Classes and constants that are stored in package.mo are also present in package.order but their relative order should be identical to the one in package.mo (this ensures that the relative order between classes and constants stored in different ways is preserved).

Mapping a Package/Class Hierarchy into a Single File (Nonstructured Entity)

When mapping a package or class-hierarchy to a file [e.g. the file A.mo], that file shall only define a single class [A.mo] with a name matching the name of the nonstructured entity. In a file hierarchy the files shall have the extension “.mo”.

A “.mo” file defining more than one class cannot be part of the mapping to file-structure and it is an error if it is loaded from the MODELICAPATH

The within Clause

A within-clause has the following syntax:

within [ packageprefixname ] ";"

A non-top-level entity shall begin with a within-clause which for the class defined in the entity specifies the location in the Modelica class hierarchy. A top-level class may contain a within-clause with no name. For a sub-entity of an enclosing structured entity, the within-clause shall designate the class of the enclosing entity; and this class must exist and must not have been defined using a short class definition.

[Example: The subpackage Rotational declared within Modelica.Mechanics has the fully qualified name Modelica.Mechanics.Rotational, which is formed by concatenating the packageprefixname with the short name of the package. The declaration of Rotational could be given as below:

within Modelica.Mechanics;
package Rotational // Modelica.Mechanics.Rotational
  ...

]

External resources

In order to reference external resources from documentation (such as links and images in html-text) and/or to reference images in the Bitmap annotation (see ). URIs should be used, for example file:/// and the URI scheme modelica:// which can be used to retrieve resources associated with a package. [Note scheme names are case-insensitive, but the lower-case form should be used, that is ‘Modelica://’ is allowed but ‘modelica://’ is the recommended form.]

The Modelica-scheme has the ability to reference a hierarchical structure of resources associated with packages. The same structure is used for all kind of resource references, independent of use (external file, image in documentation, bitmap in icon layer, and link to external file in the documentation), and regardless of the storage mechanism.

Any Modelica-scheme URI containing a slash after the package-name is interpreted as a reference to a resource. The ‘authority’ portion of the URI is interpreted as a fully qualified package name and the path portion of the URI is interpreted as the path (relative to the package) of the resource. Each storage scheme can define its own interpretation of the path (but care should be taken when converting from one storage scheme or when restructuring packages that resource references resolve to the same resource). Any storage scheme should be constrained such that a resource with a given path should be unique for any package name that precedes it. The first part of the path may not be the name of a class in the package given by the authority.

When Modelica packages are stored hierarchically in a file-system (i.e. package A in a directory A containing “package.mo”) the resource “modelica://A/Resources/C.jpg” should be stored in the file “A/Resources/C.jpg”, it is not recommend to use “modelica://A.B/C.jpg” for referencing resources; it could be stored in the file “A/B/C.jpg” - which is counter-intuitive if A.B is stored together with A. When Modelica packages are stored in other formats a similar mapping should be defined, such that a resource with a given path should be unique for any package name that precedes it. The first part of the path may not be the name of a class in the package given by the authority. As above for “Modelica 3.2.1/package.mo” i.e. resources starting from “Modelica 3.2.1”, and “modelica://Modelica.Mechanics/C.jpg” is “Modelica 3.2.1/Mechanics/C.jpg” - regardless of whether Modelica.Mechanics is stored in “Modelica 3.2.1/package.mo”, “Modelica 3.2.1/Mechanics/package.mo”, or “Modelica 3.2.1/Mechanics.mo”.

For a Modelica-package stored as a single file, “A.mo”, the resource “modelica://A/C.jpg” refers to a file “C.jpg” stored in the same directory as “A.mo”, but using resources in this variant is not recommended since multiple packages will share resources.

In case the class-name contains quoted identifiers, the single-quote “`” and any reserved characters (“:”, “/”, “?”, “#”, “[“, “]”, “@”, “!”, “$”, “&”, “(“, “)”, “*”, “+”, “,”, “;”, “=”) should be percent-encoded as normal in URIs.

[Example:

Consider a top-level package Modelica and a class Mechanics inside it, a reference such as modelica://Modelica.Mechanics/C.jpg is legal, while modelica://Modelica/Mechanics/C.jpg is illegal. The reference modelica://Modelica.Mechanics/C.jpg must also refer to a different resource than modelica://Modelica/C.jpg.]

The Modelica Library Path—MODELICAPATH

The top-level scope implicitly contains a number of classes stored externally. If a top-level name is not found at global scope, a Modelica translator shall look up additional classes in an ordered list of library roots, called MODELICAPATH. [The implementation of MODELICAPATH is tool dependent. In order that a user can work in parallel with different Modelica tools, it is advisable to not have this list as environment variable, but as a setting in the respective tool. Since MODELICAPATH is tool dependent, it is not specified in which way the list of library roots is stored. Typically, on a Windows system MODELICAPATH is a string with path names separated by “;” whereas on a Linux system it is a string with path names separated by a “:”.]

In addition a tool may define an internal list of libraries, since it is in general not advisable for a program installation to modify global environment variables. The version information for a library (as defined in ) may also be used during this search to search for a specific version of the library (e.g. if Modelica library version 2.2 is needed and the first directory in MODELICAPATH contain Modelica library version 2.1, whereas the second directory contains Modelica version 2.2, then Modelica library version 2.2 is loaded from the second directory.).

[The first part of the path A.B.C (i.e., A) is located by searching the ordered list of roots in MODELICAPATH. If no root contains A the lookup fails. If A has been found in one of the roots, the rest of the path is located in A; if that fails, the entire lookup fails without searching for A in any of the remaining roots in MODELICAPATH.]

Example of Searching MODELICAPATH

If during lookup a top-level name is not found in the unnamed top-level scope, the search continues in the package hierarchies stored in these directories. [ below shows an example MODELICAPATH = “C:library;C:lib1;C:lib2”, with three directories containing the roots of the package hierarchies Modelica, MyLib, and ComplexNumbers. The first two are represented as the subdirectories C:libraryModelica and C:lib1MyLib, whereas the third is stored as the file C:lib2ComplexNumbers.mo.

Assume that we want to access the package MyLib.Pack2 in above, e.g. through an import clause import MyLib.Pack2;. During lookup we first try to find a package MyLib corresponding to the first part of the import name. It is not found in the top-level scope since it has not previously been loaded into the environment.

Since the name was not found in the top-level scope the search continues in the directories in the MODELICAPATH in the specified order. For the search to succeed, there must be a subdirectory MyLib or a file MyLib.mo in one of the directories mentioned in the MODELICAPATH. If there is no such subdirectory or file, the lookup fails. If MyLib is found in one of the directories, the rest of the name, in this case Pack2, is located in MyLib. If that fails, the entire lookup fails without continuing the search in possibly remaining directories.

In this example the name matches the subdirectory named MyLib in the second directory “C:lib1” mentioned in the MODELICAPATH. This subdirectory must have a file package.mo containing a definition of the package MyLib, according to the Modelica rules on how to map a package hierarchy to the file system. The subpackage Pack2 is stored in its own subdirectory or file in the subdirectory MyLib. In this case the search succeeds and the package MyLib.Pack2 is loaded into the environment.]