Modules¶
Modules provide a way to structure contract specifications into blocks.
An example of a module is to group related constants such as VAT rate, payment grace period, etc. to make the contract easier to read.
Modules are specified using the module
keyword:
module Constants {
val vat = 0.25
val paymentGrace = 10 // days
}
To use declarations in a module, the ::
syntax is used:
val a = Constants::paymentGrace
// a is 10
Modules can be nested into other modules:
type BaseShape {}
module Shape {
type Circle : BaseShape {
radius : Float
}
module Circle {
val pi = 3.14159
val area = \(c : Shape::Circle) -> c.radius * c.radius * Shape::Circle::pi
}
type Rectangle : BaseShape {
length : Float,
width : Float
}
module Rectangle {
val area = \(r : Shape::Rectangle) -> r.length * r.width
}
}
// Compute area for any Shape
val area = \(s : BaseShape) ->
type x = s of {
Shape::Circle -> Shape::Circle::area x;
Shape::Rectangle -> Shape::Rectangle::area x;
_ -> 0.0
}
Notice how values are accessed in modules using the ModuleName::value
notation.
It is also possible to define contracts in modules:
module Sale {
type Sale: Event {}
val inventory = ...
template Sale(item, price, buyer) = ...
val income = ...
}
module Purchase {
type Purchase: Event {}
val stock = ...
template Purchase(item, price, seller) = ...
val expenses = ...
}
Some things to consider when working with modules:
- You must always use the full module path to refer to declarations, also when referring to other declarations inside the same module.
In the example above, we wrote
Shape::Rectangle
andShape::Circle
inside the moduleShape
to refer to the circle and rectangle types, for example. - Modules do not provide any isolation or restrict access: Any value/type/contract defined in a module is accessible with the full module path.
For more examples of using modules, see the examples.