Skip to content

Modules

Any .non file loaded with use is a module. Installing packages is in Install a Package; the standard library’s modules and what each exports are in the Standard Library reference.

FormBinds
use "path";The module, under an alias derived from the path
use "path" as name;The module, under name
use "path" { a, b };a and b directly, with no module prefix
use "path" { a as x, b };a under the name x (a itself is not bound), and b
private use "path";The module, usable in this file but not re-exported

The .non extension is added when missing. The derived alias is:

  • for a file, its stem: use "./patterns" binds patterns;
  • for a package’s src/lib.non, the package directory: use "./drums" and use "./drums/src/lib" both bind drums;
  • with hyphens replaced by underscores: use "drum-kits" binds drum_kits.
use "std/effects" { Delay as D, Reverb };
let echo = D("echo", 0.25, 0.4); // `Delay` itself is not in scope

A name a use binds has one definition in its file or selection: a second use, a fn, class or dsp definition, or a top-level let binding it too is a repeated definition, and nothing in that source runs. Rename one side with as to keep both. Across executions, the binding executed last wins: a use run after fn Delay replaces it, and running the fn again brings it back. The module is asked for the exported name, so use "./drums" { kik as k } reports that drums has no export kik.

A module’s code — its top level, its functions and its class methods — sees the module’s own top-level names and the standard library. It never sees the names of the file that imports it, so a module reads the same wherever it is used; pass what it needs as arguments.

A module exports its top-level:

  • let bindings, evaluated when the module is loaded;
  • fn, class and dsp definitions;
  • use imports, as named fields (use "./scales"; in theory makes theory.scales).

Exports are read with dot access: lib.default_bpm, lib.patterns.kick(), shapes.Circle(5).

private before a let, fn, class, dsp definition or use keeps it out of the exports. Reading it from outside is an error:

Cannot access private 'BASE_VEL' in module 'drums'

private only has an effect in a file loaded with use; at the top level of a script it is accepted and does nothing. show(module) lists private items in a separate section.

OrderPathResolves to
1std/…The standard library shipped with this resonon version
2./…, ../…Relative to the importing file
3/…The absolute path
4A bare name equal to [package].name in resonon.tomlThe project’s own src/lib.non
5Any other bare name./lib, then ./dependencies, in the project
  • The project is the nearest directory above the importing file with a resonon.toml. A file with none above it is refused before anything runs.
  • For relative and absolute paths, a package’s src/lib.non is tried first, then the file. In the project directories, the file is tried first, then the package.
  • There is no machine-wide module path and no setting that adds one. A module outside the project is reached by naming its path in the use: use "../shared-lib/src/lib" { groove };.
  • RESONON_STDLIB_PATH replaces the standard library with another copy. It takes the absolute path of an existing directory; any other value is ignored with a warning at startup.
  • The editor resolves use the same way.
  • resonon config paths prints the resolved directories. The full search order, with kits, is in Home & Search Paths.

A module that is not found is reported with every directory searched:

Module 'my_library' not found. Searched:
/music/proj/lib (project)
/music/proj/dependencies (project)

A package installed on this machine but not declared by the project gets its own message, naming the resonon install that declares it.

A package is a directory with a src/lib.non entry point, as resonon new <name> --lib creates. A bare lib.non at the top of a directory is not an entry point.

drums/
resonon.toml
src/
lib.non ← entry point
patterns.non ← imported by lib.non, exported as drums.patterns
fills.non

A standard-library module can be imported whole or by submodule; the two mix freely.

ModuleSubmodules
std/effectsstd/effects/filters, std/effects/delay, std/effects/reverb, std/effects/distortion
std/instrumentsstd/instruments/sample, std/instruments/sampler, std/instruments/melodic
use "std/effects" { Reverb };
use "std/effects/filters" { Lowpass };
  • A module is evaluated when its source, or the source of anything it imports, differs from what the session last evaluated. Otherwise the session’s copy is reused, so a module that builds a track at its top level builds it once.
  • Within one execution, a module has one version, however often it is imported.
  • RESET; clears the session, so every module is evaluated again.

Modules must form a directed acyclic graph. A cycle is an error that lists the chain:

Runtime error at 3:1: Circular import:
/music/lib/a.non
→ /music/lib/b.non
→ /music/lib/a.non
Modules must form a directed acyclic graph.

Move the definitions both sides need into a third module.

show(module) prints the module’s path, the first line of its //! documentation, its exports (functions with signatures and doc summaries, variables with types, nested modules) and its private items. show(module.function) prints one function.

┌────────────────────────────────────────┐
Module: lib (from /path/to/lib_example/src/lib.non)
Library entry point
Exports:
patterns: Module
default_bpm: Number
fn rest(beats) - Generate rests for a number of beats
Private:
INTERNAL_VEL: Number
└────────────────────────────────────────┘
  • Module files: snake_case.non.
  • Library entry points: src/lib.non.