Modules keep related declarations together. A project describes which source is the entry point and which local packages it depends on. Neither requires importing code to execute hidden initialization.
Split a program into files
Save this module as greetings.bas beside the entry file:
PUBLIC FUNCTION Greeting(name AS STRING) AS STRING
RETURN "Hello, " + name
END FUNCTIONSave the entry as main.bas:
IMPORT "greetings.bas" AS greetings
PRINT greetings.Greeting("Ada")Build main.bas. Quoted paths resolve relative to the importing file. Without AS,
the filename stem supplies the alias. Identifiers are case-insensitive; Linux file
paths are case-sensitive. Imports do not inject names unqualified or re-export
another module’s imports. Use the alias explicitly.
Only the designated entry source has executable statements. Imported modules contain declarations and imports. Cyclic source imports and cross-file recursion are supported because declarations are discovered before body checking. Unused user/imported bodies are still checked; emission prunes unreachable code.
Design a module boundary
PUBLIC exposes supported declarations; PRIVATE hides them from qualified external access. Unmodified module declarations are public for compatibility. A public signature cannot expose a private type or private error contract. Entry locals are not mutable module globals; PUBLIC DIM does not create global storage.
Save this module as counter.bas:
OPAQUE TYPE Counter
PUBLIC Label AS STRING
Value AS INTEGER
END TYPE
PUBLIC FUNCTION Create(label AS STRING) AS Counter
RETURN Counter { Label=label, Value=0 }
END FUNCTION
PUBLIC FUNCTION Current(counter AS Counter) AS INTEGER = counter.Value
PUBLIC SUB Increment(BYREF counter AS Counter)
counter.Value += 1
END SUBThis entry uses the public operations and reads the public label:
IMPORT "counter.bas" AS counters
counter = counters.Create("Visits")
counters.Increment(BYREF counter)
PRINT counter.Label
PRINT counters.Current(counter)Clients can read Label but cannot assign it, borrow it BYREF or transfer it out. Value and construction remain module-controlled. The module’s own code can mutate when ordinary exclusion rules allow it. Read-only public fields do not imply that all aliases throughout the program are globally immutable.
Create a project manifest
A basic.toml in the project directory can select an entry and dependencies:
manifest-version = 1
[project]
name = "hello"
version = "0.1.0"
[toolchain]
compiler = ">=0.1.0, <0.2.0"
[target]
kind = "executable"
root = "main.bas"
build/selfhost/stage3 build --manifest basic.toml
build/selfhost/stage3 run --manifest basic.toml -- --help
Manifest paths are relative to the declaring manifest. Arguments after -- go
to the application; run preserves its terminal I/O and exit status. help build
works without loading a project. The manifest reader supports the documented
schema-specific TOML subset, not a general-purpose TOML parser.
Depend on local packages
[dependencies]
Utilities = {path = "../utilities", version = "0.1.0"}
Graphics = {path = "../graphics/build/graphics.blib", version = "0.1.0"}
IMPORT Utilities resolves the declared alias. A source dependency names a
project directory; a prebuilt dependency names a .blib. Compiler version ranges
are checked transitively, and dependency versions can assert an exact package
version. Remote fetching, lockfiles and shared incremental analysis caches are
not implemented. Imports do not download dependencies.
For a library, set kind = "library". A .blib contains checked interfaces,
precompiled nongeneric code, generic source templates, transitive native inputs
and notices. The internal BASIL ABI is versioned; rebuild source when a package
is incompatible with the consuming toolchain. Renaming a file does not make its
ABI compatible.
Declared system native libraries use the explicit hosted linker bridge and matching SDK inputs. Ordinary static programs use the integrated emitter/linker. See the project reference for archive declarations, dependency identity, output paths and current debugging boundaries.
INTERNAL visibility is deferred and is not supported syntax. Use the implemented PUBLIC/PRIVATE module boundaries rather than relying on an intermediate package-visible access level.