Skip to content

Module Packages

Chloë Strainge edited this page Oct 14, 2026 · 1 revision

Nested modules and directory packages

A module name can resolve to a single file or a directory entry point:

app.shy
colors.shy
reports/
    init.shy
    summary.shy

import colors loads colors.shy. import reports loads reports/init.shy. The importing script does not need to know which implementation was chosen. If both reports.shy and reports/init.shy exist in one candidate directory, loading is an ambiguity error. Import the package name, never reports::init.

Assemble a public interface

A child can import its parent's public and private types with super. Public functions and variables follow normal visibility; private non-type declarations are not exposed by super.

reports/init.shy:

type InternalCount = Integer
pub import summary::{ describe }

reports/summary.shy:

import super::{ InternalCount }
pub fn describe($count: InternalCount): String { "count=${count}" }

main.shy:

import reports::{ describe }
echo (describe 9)
count=9

import super brings in the eligible parent interface; import super::{ Name } selects names. Nested paths such as reports::summary resolve child modules. pub import can make a child's selected names available through the parent.

Search rules

For ordinary imports, search beside the importing module first, then each colon-delimited directory in $SHELLY_MODULE_PATH, left to right. The first matching candidate wins. Ordinary imports never consult $SHELLY_STD_PATH.

The reserved std:: prefix searches only standard-library locations. It never uses the local-module rule or $SHELLY_MODULE_PATH. The prelude may itself be a single file or a directory package; neither representation is assumed.

A module's resolved identity and cached scope are reused rather than repeatedly executing its source. See Startup and standard library for selection and reload behavior.


Related: Modules · Startup · Conditional code

Clone this wiki locally