Packages
Introduction
Not all of the NPL code used for one particular protocol needs to be in the same file. NPL provides the concept of packages and uses to include entities from other NPL files.
Every file is contained within a package, specified by the package
statement, which must go first in a file. A package
name is a dot separated list of identifiers, for example com.noumena.bank.iou
. A missing package
directive implies
an empty package name.
It is strongly recommended, although not enforced, that all files in a package are contained in a single folder
corresponding to the package name, relative to the module source root. In the above example, this would likely be
src/main/npl/com/noumena/bank/iou
.
All symbols within a single package are automatically visible, hence the following is valid:
File inclusion/a/Foo.npl
:
package inclusion.a
protocol[party] Foo() {};
File inclusion/a/Bar.npl
:
package inclusion.a
protocol[party] Bar(f: Foo) {};
This implies that the same symbol cannot be defined in multiple files in the same package. Attempting to define Foo
in
/inclusion/a/Bar.npl
therefore produces a compiler redefinition error.
Use statement
To import a symbol from a different package, the use
statement is employed. The use
statement takes a single
argument – the fully qualified name of the imported symbol.
File inclusion/a/Foo.npl
:
package inclusion.a
protocol[party] Foo() {};
File inclusion/b/Bar.npl
:
package inclusion.b
use inclusion.a.Foo
protocol[party] Bar(f: Foo) {};
These types of symbols can be imported:
- protocols
- symbols
- structs
- identifiers
- unions
- constants
- functions (except for member functions)
These types of symbols cannot be imported:
- struct fields
- protocol fields and members
- protocol member functions
- protocol states
- actions
- local variables and function parameters
Note that fields, members and actions can be used without an explicit import, as they are inherently bound to the parent
type. For example, one does not need to import inclusion.a.SomeStruct.x
in:
File inclusion/a/Foo.npl
:
package inclusion.a
struct SomeStruct { x: Number };
File inclusion/b/Bar.npl
:
package inclusion.b
use inclusion.a.SomeStruct
function useStruct(s: SomeStruct) returns Number -> {
return s.x;
}
Prototypes
The prototypes are derived from package name instead of file name. Thus, the prototype name of SomeStruct
would be
/inclusion/a/SomeStruct
(rather than /inclusion/a/x.npl/SomeStruct
).