Skip to content
📖 The Auto Programming LanguageBook contents

Packages & Modules ​

As your programs grow from single-file scripts into substantial applications, you need a way to organize code across multiple files and directories. You also need a way to manage dependencies -- to pull in libraries written by others and keep track of which versions you're using.

Auto provides a complete project management system through automan, its package manager and build tool, combined with a module system that lets you control visibility and structure your code into clean, reusable units.

In this chapter, we'll cover:

  • Managing Projects with automan -- the package manager and build system
  • auto.toml -- the project manifest and dependency declaration
  • Defining Modules -- the mod keyword and nested modules
  • Controlling Visibility -- the pub keyword and private-by-default
  • Organizing into Files -- multi-file projects and the use keyword

Managing Projects with automan ​

automan is Auto's package manager and build tool, equivalent to Cargo for Rust or npm for Node.js. It handles creating projects, building code, running tests, and managing dependencies -- all from a single command-line tool.

Creating a New Project ​

To create a new Auto project, run automan new:

console
$ automan new my_project
     Created binary (application) `my_project` package
$ cd my_project

This generates a project with the following structure:

A new Auto project generated by `automan new`

The project directory contains two key items:

  • auto.toml -- the project manifest file (we'll explore this in detail next)
  • src/main.auto -- the entry point of the application, containing a main function

You can build and run the project with automan run, which compiles all .auto files and executes the resulting binary.

Key automan Commands ​

CommandDescription
automan new <name>Create a new project
automan buildCompile the project
automan runBuild and run
automan testRun tests
automan add <dep>Add a dependency

auto.toml ​

The auto.toml file is the project manifest. It sits at the root of your project and describes the package metadata and dependencies. It uses TOML format, the same as Rust's Cargo.toml.

Package Metadata ​

Every auto.toml starts with a [package] section:

toml
[package]
name = "my_project"
version = "0.1.0"

This tells automan the package name and version. The name must be a valid identifier -- use underscores instead of hyphens.

Declaring Dependencies ​

To use external libraries, add them to the [dependencies] section:

A project with dependencies declared in `auto.toml`

When you run automan build, it reads auto.toml, downloads the specified dependencies from the package registry, and compiles everything together. The exact versions resolved are recorded in auto.lock, ensuring reproducible builds.

Auto vs Rust Toolchain Comparison ​

ConceptAutoRust
Package managerautomancargo
Config fileauto.tomlCargo.toml
Lock fileauto.lockCargo.lock
Compilerautocrustc
Source files.auto.rs

Defining Modules ​

A module is a namespace that groups related functions, types, and constants together. In Auto, you define a module using the mod keyword followed by a block:

Defining modules with `mod`

This prints:

Server started on port 8080
Connecting to localhost

The mod keyword creates a namespace. Inside mod server { ... }, the function start is grouped under the server namespace. You access it with the dot notation: server.start().

Modules can be nested. You can place a mod block inside another mod block to create a hierarchy:

auto
mod network {
    mod tcp {
        fn listen(port int) {
            print("TCP listening on port " + port)
        }
    }
}

fn main() {
    network.tcp.listen(3000)
}

How this maps across languages:

  • Rust uses mod blocks with :: path separators. Functions inside modules are marked pub to be accessible from outside.
  • Python flattens modules into prefixed function names (server_start, client_connect).
  • C uses prefixed function names, similar to Python.
  • TypeScript uses camelCase prefixed names (serverStart, clientConnect).

Controlling Visibility ​

Auto follows Rust's philosophy: everything is private by default. Items inside a module are only visible within that module unless you explicitly mark them as public with pub.

Controlling visibility with `pub`

This prints:

public helper

The pub keyword makes helper accessible from outside the utils module. The internal function has no pub, so it's private -- only code within utils can call it. Attempting to call utils.internal() from main is a compile-time error.

This is a deliberate design choice, borrowed from Rust. Private-by-default means:

  • You must explicitly decide what to expose. The public API surface is always intentional.
  • Internal implementation details stay hidden. You can refactor the internals of a module without breaking code that uses it.
  • The compiler catches accidental access to private items at compile time.

How visibility maps across languages:

  • Rust uses the same pub keyword with the same private-by-default semantics.
  • Python has no native visibility control -- the _ prefix convention signals "internal" but isn't enforced. The transpiler comments out the call instead.
  • C uses static for file-level private functions.
  • TypeScript has no module-level visibility; the transpiler adds a // private comment and comments out the call.

Organizing into Files ​

As a project grows, you'll want to split modules across separate files. Auto follows a convention similar to Rust: each file is a module, and directories create nested module namespaces.

Project Structure ​

A typical multi-file Auto project looks like this:

text
my_project/
├── auto.toml
└── src/
    ├── main.auto
    ├── utils.auto
    └── network/
        ├── mod.auto
        ├── server.auto
        └── client.auto

Each .auto file becomes a module. The directory network/ becomes the network module namespace, with mod.auto as its entry point.

The use Keyword ​

The use keyword brings a module into scope so you can reference its items directly. This is similar to Rust's use or Python's import:

Multi-file project with `use` imports

This prints:

public helper
Server started on port 8080

use utils brings the utils module into scope. use network.server brings the server submodule from the network directory into scope. After these imports, you can call utils.helper() and server.start() directly.

Note the difference between the two use forms:

  • use utils -- imports the module as a namespace. You still access items through it: utils.helper().
  • use network.server -- imports a specific submodule. You can call its functions directly: server.start().

How use maps across languages:

  • Rust generates mod declarations for file-based modules and uses :: for paths.
  • Python generates from ... import ... statements.
  • C inlines the function definitions with comments indicating their origin.
  • TypeScript inlines the functions with comments indicating their origin module.

File Naming Conventions ​

Auto follows these conventions for file-to-module mapping:

FileModule Path
src/main.auto(binary entry point)
src/utils.autoutils
src/network/mod.autonetwork (directory module)
src/network/server.autonetwork::server
src/network/client.autonetwork::client

Each directory must have a mod.auto file to serve as the module entry point. This file can re-export submodules or define items directly.

Summary ​

Auto's package and module system provides the tools to organize code at any scale:

ConceptAutoRust
Package managerautomancargo
Project manifestauto.tomlCargo.toml
Lock fileauto.lockCargo.lock
Define modulemod name { }mod name { }
Make publicpub fnpub fn
Default visibilityprivateprivate
Import moduleuse namemod name; / use name::item;
Source files.auto.rs
Directory modulemod.automod.rs

Key design principles:

  1. Private by default: You must explicitly opt in to making items public with pub. This keeps your API surface intentional and manageable.

  2. Explicit imports: The use keyword makes dependencies between files visible at a glance. You can always see where a function comes from.

  3. Convention over configuration: File-to-module mapping follows predictable rules. src/utils.auto becomes the utils module. src/network/server.auto becomes network::server.

  4. Reproducible builds: auto.lock pins exact dependency versions, so builds are deterministic and reproducible across machines.

In the next chapter, we'll explore how Auto handles collections -- the data structures you'll use every day inside the modules you've learned to organize.

Released under the MIT License.