Chapter 3 Modules and packages
3
Chapter 3

Modules and packages

A Silk package is a named root with source files, public exports, and a manifest. Imports tell readers which package or local file supplies each symbol.

Create a package root

Keep implementation, examples, and tests in predictable folders.

Terminal
mkdir -p logger/src logger/examples logger/tests
cd logger
silk.toml
[package]
name = "logger"
version = "0.1.0"
description = "A small Silk logging package."

[sources]
root = "src/lib.slk"

Export the package surface

The source namespace can be descriptive while downstream imports use the manifest package name.

src/lib.slk
package acme::logger;

import { println } from "std/io";

export enum Level {
  Info,
  Warn,
  Error,
}

export fn write (level: Level, message: string) -> void {
  match (level) {
    Level::Info => {
      println("[info] {s}", message);
    },
    Level::Warn => {
      println("[warn] {s}", message);
    },
    Level::Error => {
      println("[error] {s}", message);
    },
  }
}

Import from an example

Quoted imports are the everyday form for stdlib, local files, and package dependencies.

examples/main.slk
package logger_example;

import logger from "logger";

fn main () -> int {
  logger::write(logger::Level::Info, "package import works");
  return 0;
}

Check the module set

Compile commands load the files and packages needed for that build.

Terminal
silk check src/lib.slk examples/main.slk
silk build examples/main.slk -o build/logger-example

Prefer quoted imports for application and package code. Direct paths such as import acme::logger::write; are useful later for ABI-oriented definitions.

What changed

  • silk.toml named the reusable package root.
  • export marked the public surface.
  • import logger from "logger"; bound a downstream namespace.
  • The example proved the package boundary without exposing private files.

Chapter complete

Next, make absence and data shape choices visible in the type system.

Continue to types and optionals