Browse the docs

Modules and imports.

Each .silk file is a module, and its path below the source root is its name. Imports bring a module, or names from it, into scope. Everything in a module is private to it until marked pub.

Syntax#

TEXT
ImportDecl  = 'pub'? 'import' ModulePath ('as' Identifier)? MemberList?
ModulePath  = Segment ('.' Segment)*
MemberList  = '{' Member (',' Member)* ','? '}'
Member      = Identifier ('as' Identifier)?
  • pub import requires a member list.

  • Imports are module-level declarations. They may also sit inside a top-level static if, as std lib modules do.

Files are modules#

  • The module name is the file's path below [package].source, without .silk, with / written as .. src/geometry/Point.silk is geometry.Point when the source root is src.

  • The source root defaults to src. See The manifest.

  • Names match file names exactly, case included. import geometry.point does not find Point.silk.

  • A directory is a module only through its barrel file mod.silk. import geometry finds src/geometry.silk or src/geometry/mod.silk, and fails when only geometry/ exists. See Barrel modules.

  • There is no module declaration inside the file.

  • A module named tests and a directory tests/ can sit side by side: tests is src/tests.silk, tests.Fakes is src/tests/Fakes.silk.

Import forms#

FormBinds
import geometry.Pointthe module, as Point (the last segment)
import geometry.Point as Pthe module, as P
import geometry.Point { Point, normSquared }the two names
import geometry.Point { normSquared as norm2 }norm2
import geometry.Shapes as S { Rect }the module as S, and Rect
  • A module binding gives qualified access: Point.normSquared(&p).

  • Members are types, functions, constants, interfaces and services the module declares or re-exports.

  • A module path whose last segment is a keyword, such as silk.match, needs as or a member list (PAR0004).

  • Std lib modules start with silk.. A dependency's modules start with the dependency name: import pricing.lib { discounted }. See The standard library and Dependencies.

Re-exports#

pub import makes the imported names part of the importing module's public surface.

silk
pub import geometry.Point { Point, normSquared as norm2 }

Another module can then write import geometry.Shapes { Point, norm2 }, or call S.norm2(...) through a module binding.

Barrel modules#

A directory's mod.silk is the module named by the directory's path, like mod.rs in Rust. It usually re-exports what the directory's other modules declare, so an importer names one module:

TEXT
src/
  main.silk
  shapes/
    mod.silk
    circle.silk
    square.silk

src/shapes/mod.silk:

silk
pub import shapes.circle { Circle }
pub import shapes.square { Square, area }

src/main.silk:

silk
import shapes { Circle, Square, area }
  • import shapes reads src/shapes.silk or src/shapes/mod.silk, whichever exists. Both existing is MOD0005.

  • A barrel is named only by its directory: import shapes.mod is MOD0006.

  • Imports inside mod.silk still start at the source root: shapes.circle, not circle.

  • The children stay importable on their own: import shapes.circle { Circle } still works.

  • import shapes inside shapes/mod.silk imports itself (MOD0002).

  • The same rule holds for a dependency's modules and for exports: exports = ["shapes"] publishes the barrel. Its children stay internal unless listed too.

  • src/mod.silk at the top of the source root is an ordinary module that no import can name.

Visibility#

  • Without pub, a declaration is visible only inside its own module. The boundary is the module, not the package.

  • pub applies separately to the type, to each field, to each method, and to the fields of each union variant.

  • A struct whose fields are not all visible cannot be built with a literal outside its module (SEM0021). Reading a private field is SEM0028.

  • A pub declaration may not mention a private type in its signature (SEM0019).

  • Impls take no pub. An impl is usable wherever its type is visible.

  • Across packages, the module must also be listed in the dependency's exports (MOD0003). See Libraries and exports.

Cycles and reachability#

  • Modules of one package may import each other in a cycle. A importing B while B imports A is fine.

  • In a program, check, build and test see the root module and every module reachable from it by imports. A file nothing imports is not checked. A library also covers every module in exports.

  • A module may import the root module: import main { execute }.

Example#

TEXT
src/
  main.silk
  geometry/
    Point.silk
    Shapes.silk

src/geometry/Point.silk:

silk
/// A point on the plane.
pub struct Point {
  pub x: i32,
  pub y: i32,
}

/// The squared distance from the origin.
pub fn normSquared(point: &Point) -> i32 {
  return point.x * point.x + point.y * point.y
}

fn secret() -> i32 {
  return 42
}

src/geometry/Shapes.silk:

silk
pub import geometry.Point { Point, normSquared as norm2 }

/// A rectangle given by two corners.
pub struct Rect {
  pub low: Point,
  pub high: Point,
}

pub fn area(rect: &Rect) -> i32 {
  return (rect.high.x - rect.low.x) * (rect.high.y - rect.low.y)
}

src/main.silk:

silk
import geometry.Point
import geometry.Shapes as S { Rect, area }

pub fn main() -> i32 {
  let corner = Point.Point { x: 3, y: 4 }
  let rect = Rect { low: Point.Point { x: 0, y: 0 }, high: move corner }
  if Point.normSquared(&rect.high) != 25 {
    return 1
  }
  if S.norm2(&rect.high) != 25 {
    return 2
  }
  return area(&rect)
}
shell
silk run; echo "exit $?"
TEXT
exit 12

Adding an import of the private secret to src/main.silk:

silk
import geometry.Point { secret }
TEXT
Checking shapes (x86_64-unknown-linux-gnu)
  load     139 modules, 3 in package         0.03s
  check    failed: 4 modules, 1 error        0.06s
[x86_64-unknown-linux-gnu]
src/main.silk:1:25: error[SEM0015] `secret` is private to geometry.Point; mark it `pub` there to use it here
Failed shapes in 0.11s

Diagnostics#

CodeMeaning
MOD0001No module at that path: Unknown module geometry.Pointt. When a std lib module with the same last segment exists elsewhere, a note names it: import silk.list adds note: did you mean `silk.collections.list`?
MOD0002A module imports itself. Only the import is reported, with no follow-on SEM0016 in that module or in modules that import it
MOD0003Another package's module that its exports does not list
MOD0004An import of Intrinsic, or of a module under it other than Intrinsic.application. Intrinsic needs no import. See The standard library for reserved names
MOD0005Both geometry.silk and geometry/mod.silk exist, so import geometry is ambiguous
MOD0006An import that names a barrel by its file name, such as import geometry.mod
SEM0014The module has no such member: Module geometry.Point has no member Nope
SEM0015The member exists but is private, or the module only imports it from another module, which the message names
SEM0016Two bindings with the same name in one scope, such as a module and a type both called Board
SEM0019A pub signature mentions a private type
SEM0021Struct literal outside its module while a field is private
SEM0028Reading a private field of another module's struct
PAR0001pub import without a member list (Expected {)
PAR0004Keyword as the last path segment with no as or member list

See also#

The manifest, The standard library, Dependencies, Libraries and exports; Structs, tuples and arrays, Enums and unions and Package parameters in the reference (parameters may only be declared in the root module); chapter 12 of the book.

View the source of this page