Module system

SCL organises code into modules. Each module is a separate compilation unit that can export definitions for use by other modules.

Creating a module

Modules are created in the Simantics Model Browser:

  1. Right-click the desired library node in the Model Browser.
  2. Select New → SCL Module.
  3. Enter the module name. The name becomes the module's path (e.g. MyLib/Utils).

The module opens in the SCL Editor View for editing. Save with Ctrl+S; the SCL Issues View shows any compilation errors immediately.

Module header

A module may begin with a header that declares its name and optional features:

module {
    features = [edo, fields]
}

The features line is only needed when using advanced syntax extensions. Currently the main feature flags are:

  • edo - enables the edo monadic block syntax — see 1.15 Functors and monads.
  • fields - enables the . record type field addressing syntax - see 1.13 Data types.

Importing modules

import makes the exported symbols of another module visible in the current module under their original names:

import "Prelude"
import "Simantics/DB"
import "Apros/Legacy"

Symbols from imported modules are accessible directly by name. If two modules export the same name, the later import wins; use qualified imports (see below) to resolve clashes.

Qualified import — import under a local alias, requiring the alias as a prefix:

import "Map" as Map
import "Set" as Set

m = Map.fromList [("a", 1)]
s = Set.fromList [1, 2, 3]

Restricted import — import only specific names:

import "Prelude" (map, filter, foldl)

Hiding import — import everything except specific names:

import "Prelude" hiding (sort)

Including modules

include makes another module's exports part of the current module's public interface — effectively re-exporting them:

include "MyLib/CommonDefs"

Use include to build aggregate modules that gather related definitions from several sub-modules. Consumers of the including module see all included symbols without needing to import each sub-module separately.

Import vs include

import include
Makes symbols locally visible Yes Yes
Re-exports symbols to importers No Yes
Typical use Using another module's functions Building aggregate / facade modules

Cyclic imports

Cyclic imports are not allowed. If module A imports module B and module B imports module A (directly or transitively), the compiler reports an error. Break the cycle by extracting shared definitions into a third module that both A and B can import.

The Prelude

The Prelude module is imported automatically into every SCL module and provides the standard library functions (map, filter, foldl, arithmetic operators, show, print, etc.). You do not need to write import "Prelude" explicitly.

Module path conventions

Module paths use / as a separator and typically follow a reversed domain / hierarchical convention:

Simantics/DB           // platform core database access
Apros/Legacy           // Apros legacy scripting API
MyProject/Analysis     // user module in "MyProject"

The path is also the string you pass to import.