Nex

Modules

Folder-as-module, declaration, imports, visibility, no .mod headers, test modules.

9.1 Folder-as-module

In Nex, a module is a directory. All .nex files within the directory belong to the same module. Subdirectories are submodules.

Given a project root, the module path is the directory path relative to the root, with / replaced by .:

src/
  linalg/
    dense/
      type.nexall three files are part of module
      arith.nexlinalg.dense
      decompose.nex
    sparse/
      matrix.nexmodule linalg.sparse
  main.nexmodule (root)

Files in the same module share visibility: any binding in one file is visible to all other files in the same module, unless declared private (see §9.4).

9.2 Module declaration

A file may optionally declare its module at the top:

module linalg.dense

def add(a: Matrix, b: Matrix) = ...

If the declaration is present, it must match the directory path. If absent, the module is determined by the directory path alone. Declaration is recommended for clarity in large codebases but never required.

9.3 Imports

Imports use the import keyword. Selective imports list the names to import; as introduces a local alias:

import math.{sqrt, abs}
import linalg.dense.{Matrix, lu_decompose as lu}
import io.console as con

Whole-module imports (import math) are not allowed — selective import is required. This prevents namespace pollution and makes dependencies explicit.

Imports must appear at the top of a file, after the optional module declaration.

9.4 Visibility

The default visibility of all module-level declarations (functions, structs, constants) is public — visible to importing modules.

The private keyword restricts a declaration to the declaring module (the whole folder, including sibling files):

module geometry

def distance(p1: Point, p2: Point) = ...    // public
private def helper(x: real) = ...           // private to geometry

Private declarations are visible to all sibling files within the same module folder but invisible to importing modules.

9.5 No .mod binary headers

Nex does not use precompiled interface files (Fortran’s .mod files, C++ modules’ BMIs, etc.). The build system compiles from source in topological order based on the import graph.

9.6 Test modules

An entire module may be marked as test-only by placing @test before the module declaration. The module’s contents — both test functions and support code — are stripped from non-test builds.

@test module stats.deep_tests

import stats.{mean, variance, stddev}

// Support code — not a test, available to tests in this module.
def make_constant_sample(n: integer, c: real) = fill(n, c)

val constant_cases = [
  (make_constant_sample(10,    0.0),  0.0),
  (make_constant_sample(100,   3.14), 3.14),
  (make_constant_sample(1000, -7.5), -7.5)
]

@test
def test_mean_recovers_constants() =
  for sample, c in constant_cases do
    assert_approx(mean(sample), c, 1e-12)
  end for

Test modules can import freely from regular modules but see only the public surface — private members of the imported modules are not visible. If a test needs an internal helper, place the @test function in the same module as the code (see the Functions chapter) rather than in a separate test module.

A test module may itself be a folder containing multiple files; each file declares @test module foo.bar.tests at the top.

Search

Esc
to navigate to open Esc to close