Modules: pub
● Intermediate3 min
pub makes a type, a function or a field visible to other modules. Without it, only the module itself sees it.
A record with a private field can be made only in its own module, so that module stays in charge of what the field holds. Another module that tries is refused:
use billing.invoice.{Invoice}
fn main() {
const inv = Invoice(id: 7, total: 1, note: "free!")
print(inv.total)
}pub type Invoice {
pub id: Int
pub total: Int
note: String
}
pub fn create(id: Int, total: Int) -> Invoice {
Invoice(id: id, total: round_up(total), note: "made by billing")
}
fn round_up(x: Int) -> Int {
(x + 9) / 10 * 10
}The compiler refused the program:
kavach run
error: `Invoice` has a private field (`note`), so only module `billing.invoice` can create one: add a `pub fn` there that makes it (spec 10.1)The fix is the one the message gives: a pub fn in billing.invoice that makes an Invoice, as create does.
An extend in the same package
An extend of a type in another file of the same package counts as the type's own module. It may read, change and build the type's private fields, so a type's methods can be spread over files without making its fields pub:
use moves
/// A wallet whose fields only its own package may touch.
pub type Wallet {
balance: Int = 0
payments: Int = 0
}use wallet.{Wallet}
extend Wallet {
pub fn open() -> Wallet {
Wallet()
}
pub fn pay_in(self, amount: Int) -> Wallet {
self with { balance: self.balance + amount, payments: self.payments + 1 }
}
pub fn summary(self) -> String {
"{self.payments} payments, {self.balance} in total"
}
}use wallet.{Wallet}
fn main() {
print(Wallet.open().pay_in(100).pay_in(50).summary())
print(Wallet.open().summary())
}The program ran and printed:
kavach run
2 payments, 150 in total0 payments, 0 in total
An extend in another package sees only pub fields.
Methods are private to their package
A method without pub can be called anywhere in its own package, so the package's modules can share helper methods without making them part of what it offers. Here pricing calls tax, and the program that uses shop can't:
use shop.{Order}
fn main() {
const o = Order(total: 200)
print(o.due())
print(o.tax())
}error: the method `tax` of `Order` is private to package `shop`: mark it `pub` there to call it here (spec 10.1) --> src/main.kav:6:13 | 6 | print(o.tax()) | ^^^
- The same holds on the type:
Order.blank()is refused outsideshopwhenblankisn'tpub. - A method an interface asks for can be called wherever the interface can,
pubor not.
Agents too
An agent is a declaration like any other. Mark it pub, and other modules can start it and call its handlers:
pub agent Picker {
on pick(items: [Int], at: Int) -> Int {
items[at]
}
}use bots
fn main() {
const bot = bots.Picker.start()
print(bot.pick([10, 20, 30], 2) catch _ => -1)
}The program ran and printed:
kavach run
30Without pub, the agent stays inside its module:
agent Picker {
on pick(items: [Int], at: Int) -> Int {
items[at]
}
}use bots
fn main() {
const bot = bots.Picker.start()
print(bot.pick([10, 20, 30], 2) catch _ => -1)
}The compiler refused the program:
kavach run
error: `Picker` is private to module `bots`: mark it `pub` there to use it here (spec 10.1)