AffineScript's module system organizes code into logical units with controlled visibility.
// In main.affine
mod math // Looks for math.affine or math/mod.affine
mod utils // Looks for utils.affine or utils/mod.affine
mod internal // Inline module definition follows
mod internal {
fn helper() -> Int { 42 }
}
Modules can contain:
- Functions
- Types (structs, enums, type aliases)
- Traits
- Effects
- Constants
- Nested modules
mod geometry {
struct Point { x: Float64, y: Float64 }
struct Circle { center: Point, radius: Float64 }
trait Shape {
fn area(self: &Self) -> Float64
}
impl Shape for Circle {
fn area(self: &Self) -> Float64 {
3.14159 * self.radius * self.radius
}
}
fn distance(p1: &Point, p2: &Point) -> Float64 {
let dx = p2.x - p1.x
let dy = p2.y - p1.y
(dx * dx + dy * dy).sqrt()
}
}
project/
├── main.affine
├── math.affine # mod math
└── utils.affine # mod utils
project/
├── main.affine
└── math/
├── mod.affine # mod math entry point
├── vectors.affine # mod vectors (inside math)
└── matrices.affine # mod matrices (inside math)
math/mod.affine:
// Declare submodules
pub mod vectors
pub mod matrices
// Re-export commonly used items
pub use vectors::Vec3
pub use matrices::Mat4
project/
├── main.affine
└── graphics/
├── mod.affine
├── renderer/
│ ├── mod.affine
│ ├── opengl.affine
│ └── vulkan.affine
└── primitives/
├── mod.affine
├── shapes.affine
└── colors.affine
Items are private by default:
mod internal {
fn private_helper() -> Int { 42 } // Private to this module
}
// main.affine
internal::private_helper() // ERROR: private function
Use pub to make items public:
mod math {
pub fn add(x: Int, y: Int) -> Int { x + y }
fn internal_helper() -> Int { 0 } // Still private
}
// main.affine
math::add(1, 2) // OK
pub // Public to everyone
pub(crate) // Public within the crate
pub(super) // Public to parent module
pub(in path) // Public to specific module path
// (no modifier) - Private to current module
Examples:
mod outer {
pub mod inner {
pub fn public_fn() { } // Everyone can access
pub(super) fn parent_only() { } // Only outer can access
pub(crate) fn crate_only() { } // Only this crate
fn private_fn() { } // Only inner can access
}
fn test() {
inner::public_fn() // OK
inner::parent_only() // OK - we're the parent
inner::private_fn() // ERROR - private
}
}
pub struct Config {
pub name: String, // Public field
pub(crate) internal: Int, // Crate-visible field
secret: String, // Private field
}
impl Config {
// Constructor needed for private fields
pub fn new(name: String, secret: String) -> Config {
Config { name, internal: 0, secret }
}
}
use math::add
use math::sub
fn main() {
add(1, 2) // No prefix needed
}
use math::{add, sub, mul, div}
use std::collections::{Vec, HashMap, HashSet}
use std::{
io::{Read, Write, BufReader},
collections::{Vec, HashMap},
fmt::Show
}
use math::* // Import all public items
// Use sparingly - can cause name conflicts
use std::collections::HashMap as Map
use graphics::renderer::opengl as gl
let map: Map[String, Int] = Map::new()
gl::init()
use std::collections::{self, HashMap}
// Now can use both:
collections::Vec // Full path
HashMap // Direct
// In lib.affine
mod internal
pub use internal::PublicType
pub use internal::public_function
pub use internal::LongTypeName as Short
// Re-export everything from a module
pub use prelude::*
// prelude.affine
pub use crate::types::{Result, Option, Error}
pub use crate::traits::{Show, Clone, Default}
pub use crate::macros::*
// Users can import everything commonly needed:
use mylib::prelude::*
// Absolute path from crate root
use crate::module::item
// Relative to current module
use self::submodule::item
// Relative to parent module
use super::sibling::item
// External crate
use external_crate::item
use std::option::Option
// Local definition shadows import
enum Option[T] {
Some(T),
None,
Unknown
}
// Use explicit path for std version
let x: std::option::Option[Int] = std::option::Some(42)
let y: Option[Int] = Unknown
use graphics::Point
use geometry::Point as GeoPoint
let screen_pt: Point = Point { x: 100, y: 200 }
let world_pt: GeoPoint = GeoPoint { x: 1.0, y: 2.0 }
// lib.affine - expose clean public API
pub mod types
pub mod traits
pub mod error
// Re-export main items at crate root
pub use types::{Config, Settings}
pub use traits::Processor
pub use error::{Error, Result}
// Keep implementation private
mod internal {
// Implementation details
}
// Conditionally compiled modules
#[cfg(feature = "async")]
pub mod async_support
#[cfg(feature = "serde")]
pub mod serialization
pub fn add(x: Int, y: Int) -> Int {
x + y
}
#[cfg(test)]
mod tests {
use super::*
#[test]
fn test_add() {
assert_eq(add(2, 2), 4)
}
}
// Public API
pub mod api {
pub use crate::core::PublicType
pub use crate::core::public_fn
}
// Internal implementation
mod core {
pub struct PublicType { ... }
pub fn public_fn() { ... }
// These stay internal
struct InternalHelper { ... }
fn internal_fn() { ... }
}
mylib/
├── affine.toml
└── src/
├── lib.affine # Crate root
├── types.affine
├── traits.affine
└── utils/
├── mod.affine
└── helpers.affine
lib.affine:
pub mod types
pub mod traits
pub mod utils
pub use types::MainType
pub use traits::MainTrait
myapp/
├── affine.toml
└── src/
├── main.affine # Binary entry point
└── lib.affine # Optional library part
myproject/
├── affine.toml
└── src/
├── main.affine # Uses lib
├── lib.affine # Library code
└── modules/
- Package Manager - Crate dependencies
- Visibility - Design rationale