Defining Modules
In this section, we’ll talk about modules and other parts of the module system, namely paths that
allow you to name items and the use keyword that brings a path into scope.
Modules Cheat Sheet
Here we provide a quick reference on how modules, paths, and the use keyword work in the compiler,
and how most developers organize their code. We’ll be going through examples of each of these rules
throughout this chapter, but this is a great place to refer to as a reminder of how modules work.
- Start from the package root: When compiling a package, the compiler first looks for code to
compile in the package root file, which is
src/lib.pntfor a library package orsrc/contract.pntfor a contract package. - Declaring modules: You can declare new modules by creating files for them in the appropriate
directories. Say you want to declare a new
gardenmodule. You have two options:- You can create the file
src/garden.pntif you want thegardenmodule to be a single file module. That is, if you don't want the modulegardento have submodules. - You can create the file
src/garden/garden.pntif you want the module to be a multi-file module. That is, if you want the modulegardento have submodules. The submodules ofgardenwould then live in thesrc/gardendirectory.
- You can create the file
- Declaring submodules: In any directory other than the package root directory, you can create
new submodules. For example, say you want to declare a submodule of
gardennamedvegetables. You have two options:- You can create the file
src/garden/vegetables.pntif you want thevegetablessubmodule to be a single file submodule. That is, if you don't want the submodulevegetablesto have its own submodules. - You can create the file
src/garden/vegetables/vegetables.pntif you want thevegetablessubmodules to be a multi-file submodule. That is, if you want the submodulevegetablesto have its own submodules.
- You can create the file
- Paths to code in modules: Once a module is part of your package, you can refer to code in that
module from anywhere else in the same package. For example, an enum
Asparagusin the garden vegetables module would be found at::garden::vegetables::Asparagus. - The
usekeyword: Within a Pint file, theusekeyword creates shortcuts to items to reduce repetition of long paths. For example, you can create a shortcut to::garden::vegetables::Asparagususing the statementuse ::garden::vegetables::Asparagus;declared at global scope in a Pint file. From then on, you only need to writeAsparagusto make use of that enum in this file.
Here, we create a contract package named backyard that illustrates these rules. The package's
directory, also named backyard, contains these files and directories:
backyard
├── pint.toml
└── src
├── contract.pnt
└── garden
├── garden.pnt
└── vegetables.pnt
The package root file is src/contract.pnt since this is a contract package. It contains:
use garden::vegetables::Asparagus;
predicate Foo(green_asparagus: Asparagus) {
constraint green_asparagus == Asparagus::Green;
}
The submodule vegetables which is defined in src/garden/vegetables.pnt, contains:
union Asparagus = Green | White | Purple;