Repository navigation
Guide packages
Mirrored from docs/guides/packages.md in the repo — that is the canonical source; edits to this wiki page are overwritten when the wiki is re-synced.
Thesis context: Packages test that the arena model scales across compilation units. The transpiler merges all reachable packages into one AST and emits a single C file — the same per-scope arena codegen, same return-slot optimization, same locally-decidable escape analysis. If the arena model depended on whole-program alias analysis, it would degrade with package count. It doesn't.
Tycho organizes code into packages. A package is a directory of
.ty files that share one flat namespace. You import a package and reach
its symbols with a qualified pkg.symbol name.
Three things define the model:
-
A package is a directory, not a file. Every
.tyfile in the directory belongs to the same package and adds to one shared namespace. -
Privacy is by leading underscore. A top-level symbol whose name starts
with
_is private to its own package: you can use it from any file within the package, but a qualifiedpkg._namefrom another package is rejected by both transpilers. Every other top-level symbol is exported. -
There's no separate compilation. The transpiler follows the import graph,
merges everything reachable into one program, and emits a single
.c.
The Packages reference is the short version; this is the longer design note.
file := package_decl? import_decl* top_def*
package_decl := "package" IDENT NEWLINE # first non-comment line
import_decl := "import" IDENT? STRING NEWLINE # optional alias, then the path
-
A package is a directory. Every
.tyfile in it declares the samepackage <name>, and<name>must equal the directory name. -
import "math/geom"binds the package under its last path component (geom);import g "math/geom"aliases it tog. Paths resolve relative to the importing package's directory. -
pkg.symbolis the qualified form for types, functions, struct/enum constructors, and enum variants —geom.Point,geom.add,geom.Red. - An imported package name is reserved in the file: a local or parameter
with that name is a compile error, so
a.bis never ambiguous. Import cycles are an error too.
proj/
main.ty # package main
geom/
point.ty # package geom
vec.ty # package geom (same package, second file)
geom/point.ty
package geom
struct Point:
x: int
y: int
fn add(a: Point, b: Point) -> Point:
return Point(a.x + b.x, a.y + b.y)
main.ty
package main
import "geom"
fn main():
r := geom.add(geom.Point(3, 4), geom.Point(1, 2))
println("sum = (" + str(r.x) + "," + str(r.y) + ")") # (4,6)
./tychoc proj/main.ty reads the main package, follows import "geom" to
proj/geom/, parses both geom files, and emits one .c with package-prefixed
symbols (geom__Point, geom__add).
The package system is a whole-program transpile, not a linker pipeline:
- The transpiler reads the entry package, follows every
import, merges all reachable definitions into one AST, and emits one.c. There's no linker step and no per-package object file. -
A file with no
packagedeclaration is a standalone single-file program. Thepackagekeyword is what switches on directory-package mode, so every single-file program compiles unchanged. -
Main-package symbols keep their plain names. Only imported packages get a
pkg__prefix, applied uniformly to every definition and reference. This includes the generated type families —Arr_geom__Pointfor[geom.Point], the_copy/_eqhelpers, and so on — so cross-package structs, enums, arrays, tuples, andResultelement types all work, keyed on the mangled type name end to end.
You rarely need to think about the mangling; it only matters when you're reading the generated C.
The standard library is reached through a collection — a named root for
imports that resolve outside the local directory tree. import "core:strings"
pulls in the corelib package strings, which sits next to the transpiler binary by
default (or at TYCHO_CORELIB if set) rather than relative to the importer. The
corelib is documented in corelib.md.
Only the core: collection is exposed today; I haven't done arbitrary named roots
(Odin's wider collection: mechanism).
Packages work the same in the C transpiler (tychoc) and the
self-hosted one (tychoc0).
tychoc0 can compile a package directly — tychoc0 path/main.ty walks the
directory and follows its imports through the same filesystem builtins — or read a
pre-bundled, post-order source stream on stdin. The C transpiler produces that
stream with tychoc --bundle <entry>: it emits imports first, with the entry
package's header rewritten to package main. tychoc0 then applies the same
package mangling in a post-parse pass — dormant unless a package declaration
showed up, so a single-file compile stays identical.
Package fixtures live in tests/pkg/<name>/ (entry main.ty, golden
tests/pkg/<name>.out). make test compiles the entry with tychoc, and
make fixpoint additionally builds each fixture with tychoc0 and checks that
tychoc0 reproduces its own emitted C byte-for-byte.
The transpiler dogfoods its own package system: compiler/pkg-split.sh splits the
self-hosted transpiler into a two-package program — rt (the leaf
C-runtime/string emitters) and main (import "rt") — derived from tychoc0.ty
by function name, with no duplicate source to maintain. It's a
real-world test that a multi-package build emits the same C as the single-file
build.
The reader docs here are mirrored from /docs in the repo — the canonical source. · tycho-lang.com · MIT licensed
- Tutorial
- The Tycho thesis: value semantics makes implicit arenas work
- Architecture & project status
- From
mallocto implicit arenas
- Tycho language reference
- Basics
- Types
- Functions and closures
- Structs and tuples
- Enums, options, and
match - Arrays and slices
- Subscripts (user-defined projections)
- Maps
- Generics
- Concurrency
- FFI (calling C)
- Packages
- Builtins
- Memory model in the self-hosted compiler
- Tycho aggregates: arrays & structs under value semantics
- Maps with arbitrary value types
m[k]as a place: in-place map-value mutation- Generics (monomorphized)
- Concurrency in Tycho
- FFI — calling C from Tycho
- Packages & modules
- corelib — Tycho's standard library
- Performance: the self-hosted transpiler vs the C one
- Debugging generated C