Mux is a statically-typed, reference-counted programming language that combines Python's readability, Go's simplicity, and Rust's type safety into one cohesive package. Write fast, safe, and maintainable code without the complexity.
- Simple & Readable: Clean syntax without semicolons, Python-like readability with Go-inspired minimalism
- Type Safe: Strong static typing with no implicit conversions. Catch errors at compile time
- Fast & Native: LLVM-powered compilation delivers native performance
- Memory Safe: Reference-counted memory management provides safety without GC pauses or complex ownership
- Modern Features: Full-featured with generics, interfaces, tagged unions, and pattern matching
- Developer Friendly: Helpful error messages, built-in tooling, and comprehensive documentation
curl -fsSL https://raw.githubusercontent.com/DerekCorniello/mux-lang/main/scripts/install.sh | shFull installation guide | Other options
Create hello.mux:
func main() returns void {
print("Hello, Mux!")
}
Run it:
mux run hello.mux- Getting Started - Installation and first steps
- Language Guide - Complete language overview
- API Reference - Language reference
- Standard Library - Built-in modules and functions
Full documentation: https://mux-lang.dev
Choose the method that works best for you:
The fastest way to get started. No Rust or LLVM required.
Linux & macOS:
curl -fsSL https://raw.githubusercontent.com/DerekCorniello/mux-lang/main/scripts/install.sh | shWindows (PowerShell):
iwr -useb https://raw.githubusercontent.com/DerekCorniello/mux-lang/main/scripts/install.ps1 | iexCustom installation directory:
MUX_INSTALL_DIR=/usr/local/bin MUX_LIB_DIR=/usr/local/lib sh install.shFor Rust developers who already have cargo installed:
cargo install mux-langNote: LLVM 17 and clang must be installed first for source builds.
For contributors and those who want the latest features:
git clone https://github.com/DerekCorniello/mux-lang
cd mux-lang
./scripts/bootstrap-dev.sh # Installs LLVM 17 automatically
./scripts/dev-cargo.sh buildmux --version # Check version
mux doctor # Validate runtime dependencies
mux doctor --dev # Validate LLVM 17 and clang for developmentMux combines familiar syntax with powerful features:
// Error handling with Result types
func divide(int a, int b) returns result<int, string> {
if b == 0 {
return err("division by zero")
}
return ok(a / b)
}
// Pattern matching with exhaustive checking
func main() returns void {
auto result = divide(10, 2)
match result {
ok(value) {
print("Result: " + value.to_string())
}
err(error) {
print("Error: " + error)
}
}
}
More examples: See the examples directory or Language Guide
Mux is an open-source project and welcomes contributions! Whether you're adding features, fixing bugs, improving documentation, or testing, your help is valuable.
- Read CONTRIBUTING.md for guidelines
- Check GitHub Issues for tasks
- Join GitHub Discussions for questions and ideas
- Current Version: 0.2.1
Mux uses the root VERSION file as the single source of truth.
- Update
VERSIONto the next release version. - Run
./scripts/sync-version.shto synchronize all Mux-owned hardcoded version fields. - If website lockfile metadata needs refresh, run
npm installinmux-website/. ./scripts/sync-version.shfails immediately ifCHANGELOG.mdis not up to date withVERSION.- License: MIT
- Maintainer: Derek Corniello
Recent changes: The runtime now uses a unified representation for optional<T> and result<T, E> at the FFI level (boxed Value pointers). Compiler-generated code and FFI should treat optionals/results as *mut Value and use the runtime discriminant helpers when inspecting variants.
Mux (fully "MuxLang") is a statically-typed, reference-counted language that combines:
- Java-style explicit typing with local type inference
- Python-style collection literals
- Rust-style pattern-matching with guards
- Curly-brace syntax and no semicolons
- Minimal trait/Class model (use
isinstead ofimplementslike Java) - Built-in
result<T,E>andoptional<T>for error handling
- Case-sensitive identifiers: letters, digits,
_, not starting with a digit - Whitespace (spaces, tabs, newlines) separates tokens
- Comments:
- Single-line:
// comment - Multi-line:
/* comment */
- Single-line:
- Statement termination: by end-of-line only (no semicolons)
- Underscore placeholder:
_can be used for unused parameters, variables, or pattern matching wildcards - Keywords:
func,returns,const,auto,class,interface,enum,match,if,else,for,while,break,continue,return,import,is,as,in,true,false,common,none,optional,result,ok,err
Type System: Mux uses strict static typing with NO implicit type conversions. All type conversions must be explicit using conversion methods.
int // 64-bit signed integer
float // 64-bit IEEE-754
bool // true | false
char // Unicode code point
string // UTF-8 sequence
Mux requires explicit type conversions for all operations. There are no implicit conversions between types.
// Integer conversions
auto x = 42
auto x_float = x.to_float() // int -> float
auto x_str = x.to_string() // int -> str
auto x_same = x.to_int() // int -> int (identity)
// Float conversions
auto pi = 3.14
auto pi_int = pi.to_int() // float -> int (truncates: 3)
auto pi_str = pi.to_string() // float -> str
auto pi_same = pi.to_float() // float -> float (identity)
// Boolean conversions
auto flag = true
auto flag_int = flag.to_int() // bool -> int (true=1, false=0)
auto flag_float = flag.to_float() // bool -> float (true=1.0, false=0.0)
auto flag_str = flag.to_string() // bool -> string ("true" or "false")
// Char conversions
auto ch = 'A'
auto ch_str = ch.to_string() // char -> str
// Method calls on literals require parentheses
auto num = (3).to_string() // Valid
auto val = (42).to_float() // Valid
// auto bad = 3.to_string() // ERROR: parsed as float 3.0
String and char parsing methods return result<T, string> because they can fail:
// String to number (returns result)
auto num_str = "42"
auto result = num_str.to_int()
match result {
ok(value) {
print("Parsed: " + value.to_string()) // "Parsed: 42"
}
err(error) {
print("Parse error: " + error)
}
}
// String to float
auto float_str = "3.14159"
auto float_result = float_str.to_float()
match float_result {
ok(value) { print(value.to_string()) }
err(msg) { print("Error: " + msg) }
}
// Char to digit (only works for '0'-'9')
auto digit_char = '5'
auto digit_result = digit_char.to_int()
match digit_result {
ok(digit) { print(digit.to_string()) } // "5"
err(msg) { print(msg) }
}
auto letter = 'A'
auto letter_result = letter.to_int()
match letter_result {
ok(_) { print("Unexpected success") }
err(msg) { print(msg) } // "Character is not a digit (0-9)"
}
The following operations are compile-time errors:
// Type mismatches in binary operations
auto bad1 = 1 + 1.0 // ERROR: cannot add int and float
auto bad2 = "hello" + 3 // ERROR: cannot add string and int
auto bad3 = true + false // ERROR: cannot add bool and bool
// Type mismatches in comparisons
auto bad4 = 1 < 1.0 // ERROR: cannot compare int and float
auto bad5 = "a" == 1 // ERROR: cannot compare string and int
// Function argument type mismatches
func takes_string(string s) returns void { }
takes_string(123) // ERROR: expected string, got int
// Correct usage requires explicit conversion
auto good1 = 1 + (1.0).to_int() // OK: 2
auto good2 = "hello" + (3).to_string() // OK: "hello3"
auto good3 = 1.to_float() < 1.0 // OK: true
auto good4 = (true).to_int() + (false).to_int() // OK: 1
| From Type | Method | Returns | Notes |
|---|---|---|---|
int |
.to_string() |
string |
Converts to string representation |
int |
.to_float() |
float |
Converts to floating-point |
int |
.to_int() |
int |
Identity function |
float |
.to_string() |
string |
Converts to string representation |
float |
.to_int() |
int |
Truncates decimal part |
float |
.to_float() |
float |
Identity function |
bool |
.to_string() |
string |
Returns "true" or "false" |
bool |
.to_int() |
int |
Returns 1 or 0 |
bool |
.to_float() |
float |
Returns 1.0 or 0.0 |
char |
.to_string() |
string |
Converts char to string |
char |
.to_int() |
result<int, string> |
Digit value for '0'-'9' only |
string |
.to_string() |
str |
Identity function |
string |
.to_int() |
result<int, string> |
Parses string as integer |
string |
.to_float() |
result<float, string> |
Parses string as float |
Mux uses a single unified type (Value enum) to represent all runtime values, enabling uniform handling in collections and generics.
pub enum Value {
Bool(bool),
Int(i64),
Float(OrderedFloat<f64>),
String(String),
List(Vec<Value>),
Map(BTreeMap<Value, Value>),
Set(BTreeSet<Value>),
Tuple(Box<Tuple>),
optional(Option<Box<Value>>),
result(result<Box<Value>, String>),
Object(ObjectRef),
}All primitives are boxed into *mut Value pointers:
- Allocation:
mux_rc_alloc(value)allocates RefHeader + Value - Storage: Pointers stored in variables, collections, and function returns
- Extraction: Typed accessors (
mux_value_get_int, etc.) unwrap values
This design enables:
- Generic collections:
list<T>works uniformly for all types - Polymorphic functions: Same function can handle any type
- Simple FFI: C code receives consistent
void*pointers
Mux maintains three distinct type representations:
| Representation | Purpose |
|---|---|
TypeNode |
AST representation, source locations |
Type |
Semantic analysis, type resolution |
BasicTypeEnum |
LLVM IR generation |
The separation enables error reporting with source locations while keeping semantic analysis LLVM-independent.
Mux provides essential built-in functions for output and utility operations. These are always available without imports.
Design Note: print is a direct runtime call that outputs to stdout. The runtime handles string formatting and newline appending.
range(int start, int end) -> list<int> - Returns a list of integers from start (inclusive) to end (exclusive). The result is always a list<int>.
// Generate indices for iteration
for i in range(0, 5) {
print(i.to_string()) // Prints 0, 1, 2, 3, 4
}
// Create a list of numbers
auto numbers = range(10, 15) // [10, 11, 12, 13, 14]
Design Note: range() is the primary way to create numeric sequences for iteration, as Mux does not support C-style for (int i = 0; i < n; i++) loops.
read_line() -> string - Reads a line from standard input and returns it as a string (excluding the newline).
print("Enter your name: ")
auto name = read_line()
print("Hello, " + name)
optional<T>
result<T, E>
list<T>
map<K,V>
set<T>
tuple<T, U>
### 3.4.1 Tuples
Tuples are fixed size pairs. A tuple always has exactly two elements.
```mux
auto pair = (1, "one")
tuple<int, string> typed = (2, "two")
print(pair.left.to_string()) // "1"
print(pair.right.to_string()) // "one"
Tuples also support to_string() and a default constructor:
auto empty = tuple<int, string>.new() // (0, "")
### 3.5 Generics
Mux supports Go/Rust-style generics with type parameters and interface bounds using the `is` keyword:
```mux
// Generic function with type constraints
func max<T is Comparable>(T a, T b) returns T {
if a > b {
return a
}
return b
}
// Generic function with Stringable bound for to_string()
func greet<T is Stringable>(T value) returns string {
return "Hello, " + value.to_string()
}
// Arithmetic operators are builtin for primitive numeric types.
// Use explicit methods or domain-specific APIs for generic composition.
// Generic class
class Stack<T> {
list<T> items
func push(T item) returns void {
self.items.push_back(item)
}
func pop() returns optional<T> {
if self.items.is_empty() { return none }
return self.items.pop_back()
}
}
Mux uses compile-time monomorphization for generics, generating specialized code for each type instantiation.
- Type inference: Determine concrete types from function arguments
- Name generation: Create unique identifier:
FunctionName$int$string$ - Type substitution: Replace type parameters with concrete types
- Code generation: Emit specialized function body
- Caching: Store generated methods to avoid regeneration
func identity<T>(T value) returns T {
return value
}
auto a = identity(42) // Generates: identity$int
auto b = identity("hello") // Generates: identity$string
The compiler substitutes types in the AST before code generation:
// Original generic function
func identity<T>(T value) returns T { ... }
// After substitution for T = int
func identity$int(int value) returns int { ... }- Zero runtime cost: No boxing, no vtables, no type checks
- Static dispatch: Methods resolved at compile time
- LLVM optimization: Each specialization can be fully optimized
The tradeoff is increased code size (one copy per type combination).
Mux provides built-in interfaces (traits) for common operations:
| Interface | Callable Method | Description |
|---|---|---|
Stringable |
.to_string() |
Types that can be converted to string |
Equatable |
(none) | Enables == and != operators |
Comparable |
(none) | Enables <, >, <=, >= operators |
Hashable |
(none) | Types that can be used as set/map keys |
Error |
.message() |
Types that can be used as result<T, E> error values |
Note: For Equatable and Comparable, the methods are marker interfaces - you cannot call .eq() or .cmp() on built-in types. Use the operators directly (==, <, etc.) instead.
Primitives and Interfaces:
int: ImplementsStringable,Equatable,Comparable,Hashablefloat: ImplementsStringable,Equatable,Comparable,Hashablestring: ImplementsStringable,Equatable,Comparable,Hashable,Errorbool: ImplementsStringable,Equatable,Hashablechar: ImplementsStringable,Equatable,Comparable,Hashable
result<T, E> requires E to implement Error.
Example: Custom Type Implementing Interface
interface Equatable {
func eq(Self) returns bool
}
class Point is Equatable {
int x
int y
func eq(Point other) returns bool {
return self.x == other.x && self.y == other.y
}
}
}
}
auto p1 = Point.new(1, 2)
auto p2 = Point.new(1, 2)
auto same = p1 == p2 // true
// Using built-in interfaces
func process<T is Stringable>(list<T> items) returns void {
for item in items {
print(item.to_string())
}
}
// Multiple bounds (AND semantics - type must implement all)
func combine<T is Comparable & Stringable>(T a, T b) returns string {
if a < b {
return a.to_string() + " < " + b.to_string()
}
return a.to_string() + " >= " + b.to_string()
}
// Type parameters must be explicitly specified
auto max_int = max<int>(3, 7) // T = int, Comparable bound satisfied
auto names = ["apple", "banana"]
print(greet<string>(names[0])) // T = string, Stringable bound satisfied
- Structs: simple aggregates
- Enums: tagged unions (see §8)
- Classes: with fields + methods (see §9)
const int MAX = 100
// Variables (explicit type required for declarations without inference)
int x = 5
bool flag = true
string name = "MuxLang"
Mux supports both explicit types and type inference with auto:
// Type inferred with 'auto'
auto x = 42 // inferred as int
auto pi = 3.14159 // inferred as float
auto name = "Mux" // inferred as str
// Explicit type annotation
int count = 0
list<string> names = []
map<string, string | int> user = {"name": "Alice", "age": 30}
// Valid inference
auto value = someFunction()
auto numbers = [1, 2, 3]
map<string, string> userMap = {"key": "value"}
// Invalid - no initializer with 'auto'
auto x // ERROR: cannot infer type without initializer
// Function parameters must be explicitly typed
func process(auto item) returns void { } // ERROR
func process(int item) returns void { } // Valid
// Unused parameter
func process(int item, int _) returns void { } // second parameter unused
All declarations require either an explicit type or auto with an initializer; semicolons are not used.
Constants are immutable values that cannot be reassigned or modified after initialization:
// Function-level constants
func calculate() returns int {
const int MULTIPLIER = 10
const float TAX_RATE = 0.08
int value = 100
return value * MULTIPLIER
}
// Constants in classes
class Config {
const int MAX_RETRIES
int current_retry
func increment() returns void {
self.current_retry++ // OK - mutable field
// self.MAX_RETRIES++ // ERROR: Cannot modify const field 'MAX_RETRIES'
}
}
auto cfg = Config.new()
cfg.current_retry = 1 // OK - mutable field
// cfg.MAX_RETRIES = 5 // ERROR: Cannot assign to const field 'MAX_RETRIES'
Const Enforcement:
- Cannot reassign:
const_var = new_value-> ERROR - Cannot use compound assignment:
const_var += 1-> ERROR - Cannot increment/decrement:
const_var++orconst_var---> ERROR - Applies to both identifiers and class fields
- Use
constwhen you want a value that won't change after initialization
func add(int a, int b) returns int {
return a + b
}
func greet(string name, int times = 1) returns void {
for i in range(0, times) {
print("Hello, " + name)
}
}
func processData() returns map<string, int> {
map<string, int> results = {"processed": 100, "skipped": 5}
auto total = results["processed"] + results["skipped"]
results["total"] = total
return results
}
// Function with unused parameters
func callback(string event, int timestamp, string _) returns void {
print("Event: " + event + " at " + timestamp)
// third parameter ignored
}
- Keyword
func - Parameter list with explicit types; default values optional
returnsclause for return type (explicit, no inference)- Body enclosed in
{…}; no semicolons - Local variables within functions can use
autoinference - Use
_for unused parameters
Mux supports standard arithmetic operations with strict type requirements (no implicit conversions):
| Operator | Description | Types | Example |
|---|---|---|---|
+ |
Addition | int, float, string |
5 + 3, "a" + "b" |
- |
Subtraction | int, float |
10 - 4 |
* |
Multiplication | int, float |
6 * 7 |
/ |
Division | int, float |
15 / 3 |
% |
Modulo | int, float |
10 % 3 |
** |
Exponentiation | int, float |
2 ** 3 |
Exponentiation Operator (**):
- Right-associative:
2 ** 3 ** 2equals2 ** (3 ** 2)= 512 - Higher precedence than
*and/:2 * 3 ** 2equals2 * 9= 18 - Works on both
intandfloattypes
auto squared = 5 ** 2 // 25
auto cubed = 2.0 ** 3.0 // 8.0
auto complex = 2 ** 3 ** 2 // 512 (right-associative)
Mux provides postfix increment (++) and decrement (--) operators with specific design constraints:
Design Constraints:
- Postfix only:
counter++is valid,++counteris not supported - Standalone only: Must appear on their own statement line, not within expressions
- Only on mutable variables: Cannot be used on
constdeclarations or literals - Type preservation: Operates on
inttypes only
auto counter = 0
counter++ // Valid: counter is now 1
counter-- // Valid: counter is now 0
// INVALID - cannot use in expressions:
// auto x = counter++ // ERROR: ++ cannot be used in expressions
// auto y = (counter++) + 5 // ERROR: standalone only
// INVALID - prefix not supported:
// ++counter // ERROR: prefix increment not supported
// INVALID - cannot modify const:
const int MAX = 100
// MAX++ // ERROR: cannot modify const
Rationale: The postfix-only, standalone-only design prevents ambiguity and side-effect confusion that can occur with prefix operators or expression-embedded increments.
| Operator | Description | Types | Example |
|---|---|---|---|
== |
Equality | All comparable types | a == b |
!= |
Inequality | All comparable types | a != b |
< |
Less than | int, float, string |
5 < 10 |
<= |
Less than or equal | int, float, string |
x <= 100 |
> |
Greater than | int, float, string |
y > 0 |
>= |
Greater than or equal | int, float, string |
age >= 18 |
&& |
Logical AND | bool |
a && b (short-circuit) |
|| |
Logical OR | bool |
a || b (short-circuit) |
! |
Logical NOT | bool |
!flag |
Short-circuit Evaluation:
&&only evaluates right side if left istrue||only evaluates right side if left isfalse
The && and || operators use LLVM control flow for short-circuit evaluation, not simple boolean operations.
Phi nodes select a value based on which predecessor block executed:
%result = phi i1 [ 0, %left_block ], [ %b_value, %right_block ]- From
left_block: constant0(left was false) - From
right_block: computed%b_value(left was true)
If LLVM generated a && b as a single expression:
- Both
aandbwould always be evaluated (no short-circuit) - No opportunity for branch prediction
- Can't exploit constant operands
The basic block approach preserves semantics while enabling LLVM optimizations (dead code elimination, inlining, vectorization).
The in operator tests for membership/containment with strict type requirements:
| Left Operand | Right Operand | Description |
|---|---|---|
T |
list<T> |
Check if value exists in list |
T |
set<T> |
Check if value exists in set |
string |
string |
Check if substring exists |
char |
string |
Check if character exists in string |
Type Constraints:
- Both operands must have compatible element types
- No implicit type conversions allowed
- Returns
bool
// List containment
auto nums = [1, 2, 3, 4, 5]
auto hasThree = 3 in nums // true
auto hasTen = 10 in nums // false
// Set containment
auto tags = {"urgent", "important"}
auto isUrgent = "urgent" in tags // true
// String containment
auto msg = "hello world"
auto hasWorld = "world" in msg // true
auto hasFoo = "foo" in msg // false
// Character in string
auto hasO = 'o' in msg // true
auto hasZ = 'z' in msg // false
// INVALID - type mismatch:
// auto bad = "1" in nums // ERROR: string not in list<int>
// auto bad2 = 1 in msg // ERROR: int not in string
The + operator is overloaded for collection types with type-specific semantics:
| Types | Operation | result |
|---|---|---|
list<T> + list<T> |
Concatenation | Combined list |
map<K,V> + map<K,V> |
Merge | Combined map (latter overwrites former on key collision) |
set<T> + set<T> |
Union | Set containing all unique elements |
string + string |
Concatenation | Combined string |
Operators are built-in for primitive types and collections.
| Operator | Types |
|---|---|
+ |
int, float, string, list, map, set |
- |
int, float |
* |
int, float |
/ |
int, float |
% |
int, float |
** |
int, float |
== |
all types |
<, >, <=, >= |
int, float, string, char |
The semantic analyzer checks operator types:
// For a + b
let left_type = analyzer.get_expression_type(left_expr)?;
let right_type = analyzer.get_expression_type(right_expr)?;
if !type_supports_addition(&left_type) {
return err(format!("Type {} does not support +", left_type));
}For primitive types, direct LLVM operations:
%result = add i64 %a, %bArithmetic operators are not dispatched through Add/Sub/Mul/Div interfaces.
They are validated semantically and lowered to builtin operations for supported types.
Type Constraints:
- Both operands must be the exact same collection type
- No mixing of collection types (e.g.,
list + setis an error) - No implicit element type conversions
// List concatenation
auto list1 = [1, 2]
auto list2 = [3, 4]
auto combined = list1 + list2 // [1, 2, 3, 4]
// Map merge (latter wins on key collision)
auto map1 = {"a": 1, "b": 2}
auto map2 = {"b": 3, "c": 4} // Note: key "b" exists in both
auto merged = map1 + map2 // {"a": 1, "b": 3, "c": 4}
// Set union
auto set1 = {1, 2, 3}
auto set2 = {3, 4, 5}
auto unioned = set1 + set2 // {1, 2, 3, 4, 5}
// String concatenation
auto greeting = "Hello, " + "World" // "Hello, World"
// INVALID - type mismatch:
// auto bad = [1, 2] + {3, 4} // ERROR: cannot add list and set
// auto bad2 = [1, 2] + [3.0, 4.0] // ERROR: list<int> + list<float>
// Block-form lambda with explicit types and return type
auto square = func(int n) returns int {
return n * n
}
auto doubler = func(float x) returns float {
return x * 2.0
}
// Passing lambdas to functions
auto result = apply(10, func(int x) returns int {
return x + 5
})
// Lambda with unused parameters
auto processFirst = func(int first, int _) returns int {
return first * 2 // second parameter ignored
}
// Block-form lambda with mixed explicit/inferred types
auto filter = func(list<int> nums, func(int) returns bool cond) returns list<int> {
list<int> out = []
for n in nums {
if cond(n) {
out.push_back(n)
}
}
return out
}
- All lambdas use block syntax with
func(params) { ... } - Lambda parameters can use
autowhen type can be inferred from context - Use
_for unused lambda parameters - optional capture list in
[…]form [needs more clarification]
if x > 0 {
print("positive")
} else if x < 0 {
print("negative")
} else {
print("zero")
}
// With type inference
auto message = if x > 0 { "positive" } else { "non-positive" }
match (value) {
some(v) if v > 10 {
auto msg = "large: " + v // local inference
print(msg)
}
some(v) {
print("small: " + v)
}
none {
print("no value")
}
_ {
print("unexpected case") // wildcard pattern
}
}
Match statements can be used as switch statements for any type:
// Match on int literals (like a switch)
auto status = 200
match status {
200 { print("OK") }
404 { print("Not Found") }
500 { print("Server Error") }
_ { print("Unknown status") }
}
// Match on string literals
auto command = "start"
match command {
"start" { print("Starting...") }
"stop" { print("Stopping...") }
"restart" { print("Restarting...") }
_ { print("Unknown command") }
}
// Variable binding in patterns
auto value = 42
match value {
1 { print("one") }
captured { print("got: " + captured.to_string()) }
_ { print("other") }
}
// List literal matching
auto nums = [1, 2, 3]
match nums {
[] { print("empty") }
[1, 2, 3] { print("three elements") }
[first, ..rest] { print("has elements") }
}
// Switch with guards
auto score = 85
match score {
n if n >= 90 { print("A") }
n if n >= 80 { print("B") }
n if n >= 70 { print("C") }
n if n >= 60 { print("D") }
_ { print("F") }
}
for item in myList {
auto processed = transform(item) // type inferred
print(processed)
}
// Iterator with inference
for item in collection {
// item type inferred from collection element type
process(item)
}
// Ignoring loop variables when not needed
for _ in range(0, 10) {
doSomething() // don't care about the index
}
// Destructuring in loops with unused parts
for (key, _) in keyValuePairs {
print("Key: " + key) // value ignored
}
while cond {
auto currentTime = getCurrentTime() // local inference
// ...
}
Works as in C/Java.
enum Shape {
Circle(float radius)
Rectangle(float width, float height)
Square(float size)
}
enum Shape {
Circle(float radius)
Rectangle(float width, float height)
Square(float size)
}
// Usage with inference
auto myShape = Circle.new(5.0) // type inferred as Shape
list<Shape> shapes = [Circle.new(1.0), Rectangle.new(2.0, 3.0)]
// Pattern matching with unused enum data
match (shape) {
Circle(_) {
print("It's a circle") // radius value ignored
}
Rectangle(width, _) {
print("Rectangle with width: " + width) // height ignored
}
Square(size) {
print("Square with size: " + size)
}
}
Each variant may carry data. Pattern-match with destructuring and guards. Use _ to ignore unused enum data in patterns.
interface Drawable {
func draw() returns void
}
class Circle is Drawable, ShapeLike {
float radius // explicit type required for fields
func draw() returns void {
auto message = "Circle radius=" + radius // local inference in methods
print(message)
}
func area() returns float {
const float PI = 3.1415 // inferred as float
return PI * radius * radius
}
// Method with unused parameters
func resize(float newRadius, string _) returns void {
radius = newRadius // second parameter ignored
}
}
// Generic class example
class Stack<T> {
list<T> items
func push(T item) returns void {
items.push_back(item)
}
func pop() returns optional<T> {
if items.isEmpty() {
return none
}
auto item = items.pop_back()
return some(item)
}
}
// Usage with inference
auto circle = Circle.new(5.0) // type inferred as Circle
list<Drawable> shapes = [circle]
Stack<int> intStack = Stack<int>.new() // explicit generic instantiation with .new()
Mux uses the common keyword to declare static (class-level) methods that can be called without an instance. This is distinct from const which declares immutable values.
common vs const:
| Keyword | Purpose | Usage | Example |
|---|---|---|---|
common |
Static methods and factory functions | Called on the class itself, not instances | ClassName.method() |
const |
Immutable constants | Values that cannot change after initialization | const int MAX = 100 |
class Stack<T> {
list<T> items
// Instance method - called on instances
func push(T item) returns void {
self.items.push_back(item)
}
// Static method - called on the class
common func who_am_i() returns string {
return "I'm a Stack!"
}
// Factory pattern - static method that creates instances
common func from(list<T> init_list) returns Stack<T> {
auto new_stack = Stack<T>.new()
new_stack.items = init_list
return new_stack
}
}
// Calling static methods
print(Stack.who_am_i()) // "I'm a Stack!"
auto s = Stack<int>.from([1, 2, 3]) // Factory method
// Calling instance methods
auto stack = Stack<int>.new()
stack.push(42) // Instance method
Key Differences:
- Instance methods (no keyword) operate on
selfand require an instance - Static methods (
common) have noselfand are called on the class - Const fields are immutable instance/class fields, not methods
- Static methods cannot access instance fields (no
selfcontext) - Factory patterns commonly use
common func from(...)to create instances with pre-populated data
Classes are instantiated using the .new() method pattern:
// Basic instantiation
auto circle = Circle.new() // No constructor arguments
auto circle2 = Circle.new(5.0) // With constructor arguments
// Generic class instantiation
auto int_stack = Stack<int>.new()
auto string_stack = Stack<string>.new()
// Using factory methods
auto prebuilt = Stack<int>.from([1, 2, 3])
auto pair = Pair<string, int>.from("key", 42)
Mux objects use Rust's Rc<Arc<ObjectData>> pattern for shared ownership with type information.
struct ObjectData {
ptr: *mut c_void, // User's object data
type_id: TypeId, // Runtime type identifier
size: usize, // Size for deallocation
ref_count: AtomicUsize, // Reference count
}
struct ObjectRef {
data: Rc<ObjectData>, // Shared ownership
}lazy_static::lazy_static! {
static ref TYPE_REGISTRY: Mutex<HashMap<TypeId, ObjectType>> = ...
static ref NEXT_TYPE_ID: AtomicUsize = ...
}
pub struct ObjectType {
pub id: TypeId,
pub name: String,
pub size: usize,
pub destructor: Option<fn(*mut c_void)>,
}Each class registers with the runtime, receiving a unique TypeId.
pub fn alloc_object(type_id: TypeId) -> *mut Value {
let obj_type = TYPE_REGISTRY.lock().get(&type_id);
let size = obj_type.size;
let ptr = std::alloc::alloc(size);
let obj_ref = ObjectRef::new(ptr, type_id, size);
mux_rc_alloc(Value::Object(obj_ref))
}- Type information at runtime:
type_idenables type checks and casts - Proper cleanup:
sizeand optional destructor for cleanup - Shared ownership: Multiple references to same object
Design Note: Mux uses explicit .new() rather than direct constructor calls to distinguish class instantiation from function calls and enum variant construction.
Mux uses static dispatch for interfaces - no runtime vtable lookup.
VTables are generated at compile time:
@vtable_Circle = constant {
i32, // type tag
void (i8*)* // draw method pointer
} {
i32 1, // Circle's type ID
void (i8*)* @Circle.draw
}Methods are prefixed with their class name:
class Circle {
func draw() returns void { ... }
}
Generates LLVM function: Circle.draw
- Zero cost: No pointer indirection, direct function calls
- Inlining: LLVM can inline interface methods
- Optimization: Better branch prediction, no indirect jumps
// Dynamic dispatch (Python, Java)
circle.draw() // Look up vtable, find slot, call
// Static dispatch (Mux)
Circle.draw() // Direct call to Circle.drawThe tradeoff: interfaces cannot be added to types from other modules (no "extension traits").
// Explicit typing
list<int> nums = [1, 2, 3, 4]
map<string, int> scores = {"Alice": 90, "Bob": 85}
// With type inference
auto nums = [1, 2, 3, 4] // inferred as list<int>
map<string, int> scores = {"Alice": 90, "Bob": 85}
// mixed = [1, 2.5, 3] // ERROR: conflicting types, explicit type needed
// Nested collections
list<list<int>> matrix = [[1, 2], [3, 4]]
map<string, list<int>> lookup = {"users": [1, 2, 3], "admins": [4, 5]}
// Complex nested structures
auto users = [
{"name": "Alice", "scores": [95, 87, 92]},
{"name": "Bob", "scores": [78, 85, 90]}
] // inferred as list<map<string, string | list<int>>>
auto data = {
"numbers": [1, 2, 3, 4, 5],
"metadata": {"version": "1.0", "count": 5}
} // inferred as map<string, list<int> | map<string, string | int>>
// Generic collections
list<Pair<int, string>> pairs = [Pair.new(1, "one"), Pair.new(2, "two")]
list<Container<int>> containers = list<Container<int>>()
All collections provide a consistent API for access, mutation, and inspection.
| Method | Returns | Description |
|---|---|---|
.size() |
int |
Returns the number of elements in the list |
.is_empty() |
bool |
Returns true if list has no elements |
.get(int index) |
optional<T> |
Safe access; returns some(value) or none if out of bounds |
[int index] |
T |
Direct access; runtime error if out of bounds |
.push(T item) |
void |
Appends item to the end of the list (alias for push_back) |
.push_back(T item) |
void |
Appends item to the end of the list |
.pop() |
optional<T> |
Removes and returns last item, or none if empty (alias for pop_back) |
.pop_back() |
optional<T> |
Removes and returns last item, or none if empty |
.to_string() |
string |
Returns a string representation of the list |
auto nums = [1, 2, 3]
// Safe access with optional
match nums.get(0) {
some(first) { print(first.to_string()) } // "1"
none { print("Index out of bounds") }
}
// Direct access (runtime error if index invalid)
auto second = nums[1] // 2
// Mutation
nums.push_back(4) // [1, 2, 3, 4]
match nums.pop_back() {
some(last) { print(last.to_string()) } // "4"
none { }
}
// Inspection
print(nums.size().to_string()) // "3"
print(nums.is_empty().to_string()) // "false"
| Method | Returns | Description |
|---|---|---|
.size() |
int |
Returns the number of key-value pairs |
.is_empty() |
bool |
Returns true if map has no entries |
.get(K key) |
optional<V> |
Safe lookup; returns some(value) or none if key not found |
[K key] |
V |
Direct access; runtime error if key not found |
.put(K key, V value) |
void |
Inserts or updates a key-value pair |
.contains(K key) |
bool |
Returns true if key exists in map |
.remove(K key) |
optional<V> |
Removes key and returns value, or none if key not found |
.to_string() |
string |
Returns a string representation of the map |
auto scores = {"Alice": 90, "Bob": 85}
// Safe access
match scores.get("Alice") {
some(score) { print(score.to_string()) } // "90"
none { print("Student not found") }
}
// Direct access
auto bobScore = scores["Bob"] // 85
// Map entries are immutable; reassign to update
scores["Alice"] = 95 // Updates existing key
| Method | Returns | Description |
|---|---|---|
.size() |
int |
Returns the number of elements |
.is_empty() |
bool |
Returns true if set is empty |
.add(T item) |
void |
Adds an item to the set |
.contains(T item) |
bool |
Returns true if item exists in set |
.remove(T item) |
optional<T> |
Removes item and returns it, or none if not found |
.to_string() |
string |
Returns a string representation of the set |
auto tags = {"urgent", "important", "review"}
print(tags.size().to_string()) // "3"
// Add and check membership
tags.add("priority")
if tags.contains("urgent") {
print("Has urgent tag")
}
// Remove item
match tags.remove("review") {
some(removed) { print("Removed: " + removed) }
none { print("Item not found") }
}
Design Note: Collections use consistent method naming across all types. Safe access via .get() returns optional<T>, while direct access with [] provides unchecked access with runtime bounds checking.
Mux's collections (list, map, set) can contain any Value, enabling arbitrary nesting.
| Collection | Rust Type | Use Case |
|---|---|---|
list<T> |
Vec<Value> |
Contiguous array, indexed access |
map<K,V> |
BTreeMap<Value, Value> |
Key-value pairs, sorted keys |
set<T> |
BTreeSet<Value> |
Unique elements, membership test |
Unlike HashMap/HashSet, BTree variants provide:
- Deterministic iteration order: Always the same order
- Ordered operations: First/last element, range queries
- Reproducible output:
to_string()produces consistent results
auto nested = [
{"name": "Alice", "scores": [95, 87, 92]},
{"name": "Bob", "scores": [78, 85, 90]}
]
// Structure: list<map<string, list<int> | string>>
The type system tracks nesting through:
- Parser: Creates nested
TypeNodestructures - Semantic Analyzer: Resolves to
Type::List(Type::Map(...)) - Code Generator: Creates appropriate LLVM types
Collections are RC-allocated and contain RC-allocated values. When freed:
- Collection's refcount reaches zero
- Collection's
Vec<Value>is dropped - Each contained
Valuehas its refcount decremented - Nested collections are freed recursively
func divide(int a, int b) returns result<int, string> {
if b == 0 {
return err("division by zero")
}
return ok(a / b)
}
// Usage with inference
auto result = divide(10, 2) // inferred as result<int, string>
match result {
ok(value) {
auto message = "result: " + value // local inference
print(message)
}
err(error) {
print("Error: " + error)
}
_ {
print("Unexpected result") // wildcard for completeness
}
}
// Ignoring error details when not needed
match result {
ok(value) {
print("Success: " + value)
}
err(_) {
print("some error occurred") // error details ignored
}
}
| Method | Returns | Description |
|---|---|---|
.is_ok() |
bool |
Returns true if the result is an ok variant |
.is_err() |
bool |
Returns true if the result is an err variant |
.to_string() |
string |
String representation |
result<int, string> res1 = ok(42)
result<int, string> res2 = err("error")
print(res1.is_ok().to_string()) // true
print(res1.is_err().to_string()) // false
print(res2.is_ok().to_string()) // false
print(res2.is_err().to_string()) // true
func findEven(list<int> xs) returns optional<int> {
for x in xs {
if x % 2 == 0 {
return some(x)
}
}
return none
}
// Usage with inference
optional<int> maybeEven = findEven([1, 3, 4, 7]) // inferred as optional<int>
match maybeEven {
some(value) {
print("Found even: " + value)
}
none {
print("No even number found")
}
_ {
print("Unexpected optional state")
}
}
// Ignoring the wrapped value when you just care about presence
match maybeEven {
some(_) {
print("Got a value") // don't care what the value is
}
none {
print("Got nothing")
}
}
| Method | Returns | Description |
|---|---|---|
.is_some() |
bool |
Returns true if the optional contains a value |
.is_none() |
bool |
Returns true if the optional is empty |
.to_string() |
string |
String representation |
optional<int> opt1 = some(42)
optional<int> opt2 = none
print(opt1.is_some().to_string()) // true
print(opt1.is_none().to_string()) // false
print(opt2.is_some().to_string()) // false
print(opt2.is_none().to_string()) // true
Use match to unpack results and optionals. Use _ to ignore unused values in patterns.
Both result<T, E> and optional<T> use a uniform runtime representation.
pub struct result<T, E> {
discriminant: i32, // 0 = ok, 1 = err
data: *mut T, // pointer to value
}
pub struct optional<T> {
discriminant: i32, // 0 = none, 1 = some
data: *mut T, // pointer to value
}Same layout enables generic code to work with either type.
Discriminant: Determines which variant is active Data pointer: Points to the contained value (boxed like all other values)
auto opt = some(42) // discriminant=1, data=box(42)
auto res = ok("error") // discriminant=0, data=box("error")
- Single runtime representation: Collections can store either
- No enum overhead: No runtime enum tag beyond discriminant
- Error propagation: Easy to implement with match statements
- Interop: optional and result can wrap the same types
- Reference-counted runtime; deterministic memory management with no manual
free - All objects and collections live on the heap
- Primitives passed by value, objects by reference
Mux uses atomic reference counting for deterministic memory management. Every heap-allocated value is prefixed with a reference count header.
┌──────────────────┬─────────────┐
│ RefHeader │ Value │
│ ref_count: u64 │ (payload) │
└──────────────────┴─────────────┘
^
Allocation pointer
The RefHeader uses AtomicUsize for thread-safe atomic operations. The Value payload contains the actual data.
Increment (mux_rc_inc): Called when creating a new reference:
- Assigning to a new variable
- Passing as a function argument
- Adding to a collection
Decrement (mux_rc_dec): Called when a reference goes out of scope:
- Variable assignment is overwritten
- Function returns (cleanup of local variables)
When mux_rc_dec returns true, the refcount reached zero and memory is freed automatically.
The compiler generates cleanup code using a scope stack:
- Enter scope ->
push_rc_scope()(function entry, if-block, loop-body, match-arm) - Track variable ->
track_rc_variable(name, alloca)for each RC-allocated variable - Exit scope ->
generate_all_scopes_cleanup()iterates through all scopes in reverse order
This ensures proper cleanup order and handles early returns.
Mux uses references for safe memory access and manipulation:
&Tdenotes a reference to typeT&exprcreates a reference toexpr- References are automatically dereferenced when used
- No pointer arithmetic is allowed
- References are non-nullable by default
- Use
Option<&T>for nullable references
// Basic reference usage
int x = 10
auto r = &x // r is of type &int
print("ref value: " + (*r).to_string()) // 10 - explicit dereference with *
*r = 20 // Changes x to 20 via dereference
print("val after ref update: " + (*r).to_string()) // 20
print("x is now: " + x.to_string()) // 20
// References to list elements
auto numbers = [1, 2, 3, 4, 5]
auto first = &numbers[0] // &int
print("first element: " + (*first).to_string()) // 1
// Function taking a reference
func update(&int ref) returns void {
*ref = *ref + 1 // Must explicitly dereference to modify
}
update(&x)
print("val after update: " + x.to_string()) // 21
Reference Syntax:
- Create reference:
&variableor&expression - Dereference:
*reference(required for both reading and writing) - Pass to functions:
func(&int ref)declares parameter,update(&x)passes reference - References to references: Not supported
Design Note: Unlike some languages with automatic dereferencing, Mux requires explicit * for all reference operations. This makes memory access patterns explicit and prevents accidental mutation bugs.
import math
import std.math
import shapes.circle as circle
// Usage with inference
float pi = math.PI // type inferred from math module
float root = math.sqrt(9.0)
auto c = circle.new(5.0) // type inferred from constructor
// Import with unused alias for completeness
import utils.logger as _ // imported but not directly used in this scope
- Python-style imports only
- Module paths map directly to file paths
- Imported symbols can be used with type inference
- Use
_alias when importing for side effects only - Standard library modules are imported as
import std.<module>and used as<module>.<item>
Mux uses Python-style module imports with compile-time resolution.
import math // math.mux in same directory
import shapes.circle // shapes/circle.mux
import std.math // stdlib math module
File paths map to module paths:
import foo->foo.muximport shapes.circle->shapes/circle.muximport std.math-> stdlibmathmodule namespace (math.*)
Functions from imported modules use mangled names:
// math.mux
func fibonacci(int n) returns int { ... }
// main.mux
import math
auto result = math.fibonacci(10)
Generates: math!fibonacci (not fibonacci)
This prevents conflicts when multiple modules define functions with the same name.
Top-level statements in modules become a module initialization function:
// config.mux
const int MAX_USERS = 100
auto initialized = false
func init() returns void {
initialized = true
}
The compiler generates:
define void @config.init() { ... }And calls it before main() executes.
The user-defined entry function is func main() returns void.
Mux allows explicit calls to main() from user code (for example in helper functions
or top-level statements). These calls target the user entry function body.
func main() returns void {
print("main body")
}
main()
If you also call main() manually, remember that the program entrypoint will still
invoke main() once during normal startup, so main may run multiple times.
The compiler:
- Parses all imports
- Builds dependency graph
- Processes modules in topological order
- Generates initialization functions for each module
Recommended:
- Local variables with obvious initialization
- Complex generic types that are clear from context
- Temporary variables in calculations
- Iterator variables in loops
// These require explicit types due to ambiguity
list<int> empty = [] // empty collection needs explicit type
auto empty = list<int>() // or explicit constructor
result<int, string> pending // uninitialized variables need explicit type
// Generic instantiation may need explicit types
Stack[int] stack = Stack[int]() // explicit generic parameter
auto pairs = zip<int, string>(numbers, names) // when inference is ambiguous
// Good uses of underscore
func process(int data, string _) { } // ignore second parameter
for _ in range(0, 10) { } // ignore loop counter
match result { ok(_) { } } // ignore success value
// Avoid overusing underscore when names would help readability
// Less clear:
func calculate(int _, int _, float _) returns float { }
// Better:
func calculate(int width, int height, float _) returns float { }
import math
const float PI = 3.14159 // inferred as float
enum MaybeValue<T> {
some(T)
none
}
interface Shape {
func area() returns float
}
class Circle is Shape {
float r // explicit type required for fields
func area() returns float {
return PI * r * r
}
}
// Generic utility function
func map<T, U>(list<T> items, func(T) returns U transform) returns list<U> {
auto result = list<U>()
for item in items {
result.push_back(transform(item))
}
return result
}
func main() returns void {
auto shapes = [Circle.new(2.0), Circle.new(3.5)] // inferred as list<Circle>
for shape in shapes {
float area = shape.area() // inferred as float
string message = "Area: " + area // inferred as str
print(message)
}
// Working with Results and inference
auto results = list<result<float, string>>()
for shape in shapes {
auto areaResult = ok(shape.area()) // inferred as result<float, string>
results.push_back(areaResult)
}
// Using generics with inference and lambdas
auto areas = map(shapes, func(Shape s) {
return s.area() // inferred as list<float>
})
auto descriptions = map(areas, func(string a) {
return "Area: " + a // inferred as list<string>
})
// Pattern matching with underscore
for result in results {
match result {
ok(value) {
print("Success: " + value)
}
err(_) {
print("Error occurred") // don't care about error details
}
}
}
}
The Mux standard library includes assert, math, io, random, datetime, sync, net, env, data, and sql.
Import styles:
import std // use std.assert, std.math, std.io, std.random, std.datetime, std.sync, std.net, std.env, std.data, std.sql
import std.assert // use assert.*
import std.math // use math.*
import std.io // use io.*
import std.random // use random.*
import std.datetime // use datetime.*
import std.sync // use sync.*
import std.net // use net.*
import std.env // use env.*
import std.data // use data.*
import std.sql // use sql.*
import std.(math, random as r)
import std.* // flat import of stdlib items
assert provides test assertions that panic immediately on failure with descriptive error messages.
assert.assert_true(bool condition) -> void- Panics if falseassert.assert_false(bool condition) -> void- Panics if trueassert.assert(bool condition, string message) -> void- Panics with custom message if falseassert.assert_eq(T actual, T expected) -> void- Panics if values differ (generic)assert.assert_ne(T actual, T expected) -> void- Panics if values equal (generic)assert.assert_some(optional<T> value) -> void- Panics if noneassert.assert_none(optional<T> value) -> void- Panics if someassert.assert_ok(result<T, E> value) -> void- Panics if errassert.assert_err(result<T, E> value) -> void- Panics if ok
math provides floating-point constants and functions.
- Constants:
math.pi,math.e - Unary functions:
sqrt,sin,cos,tan,asin,acos,atan,ln,log2,log10,exp,abs,floor,ceil,round - Binary functions:
atan2,log,min,max,hypot,pow
io provides filesystem and path operations with explicit error handling via result<T, string>.
- File operations:
read_file,write_file,exists,remove,mkdir,listdir - Path operations:
is_file,is_dir,join,basename,dirname
random provides pseudorandom generation:
random.seed(int seed) -> voidrandom.next_int() -> intrandom.next_range(int min, int max) -> intrandom.next_float() -> floatrandom.next_bool() -> bool
datetime provides Unix-timestamp based date and time helpers.
datetime.now() -> result<int, string>(seconds since Unix epoch, UTC)datetime.now_millis() -> result<int, string>(milliseconds since Unix epoch, UTC)datetime.year(int ts) -> result<int, string>datetime.month(int ts) -> result<int, string>datetime.day(int ts) -> result<int, string>datetime.hour(int ts) -> result<int, string>datetime.minute(int ts) -> result<int, string>datetime.second(int ts) -> result<int, string>datetime.weekday(int ts) -> result<int, string>where0=Sun ... 6=Satdatetime.format(int ts, string pattern) -> result<string, string>(UTC)datetime.format_local(int ts, string pattern) -> result<string, string>(local timezone)datetime.sleep(int seconds) -> result<void, string>(blocking at call site)datetime.sleep_millis(int milliseconds) -> result<void, string>(blocking at call site)
Format patterns use chrono strftime tokens, for example:
%Afull weekday name%aabbreviated weekday name%Bfull month name%babbreviated month name%Y-%m-%d %H:%M:%S
sync provides basic concurrency primitives.
-
sync.spawn(fn() -> void) -> result<Thread, string> -
sync.sleep(int milliseconds) -> void -
Thread.join() -> result<void, string> -
Thread.detach() -> result<void, string> -
Mutex.new() -> Mutex -
Mutex.lock() -> result<void, string> -
Mutex.unlock() -> result<void, string> -
RwLock.new() -> RwLock -
RwLock.read_lock() -> result<void, string> -
RwLock.write_lock() -> result<void, string> -
RwLock.unlock() -> result<void, string> -
CondVar.new() -> CondVar -
CondVar.wait(Mutex) -> result<void, string> -
CondVar.signal() -> result<void, string> -
CondVar.broadcast() -> result<void, string>
net exposes TCP/UDP sockets plus HTTP client/server primitives with JSON request and response shapes.
net.TcpStream.connect(string addr) -> result<TcpStream, string>net.TcpListener.bind(string addr) -> result<TcpListener, string>listener.accept() -> result<TcpStream, string>net.UdpSocket.bind(string addr) -> result<UdpSocket, string>net.http.request(Json req) -> result<Json, string>net.http.read_request(TcpStream stream) -> result<Json, string>net.http.write_response(TcpStream stream, Json response) -> result<void, string>write_responseserializes body as JSON and defaultsContent-Typetoapplication/jsonunless you set it inheaders.net.TcpStream.read(int size),net.TcpStream.write(list<int> bytes)net.UdpSocket.send_to(list<int> bytes, string addr),net.UdpSocket.recv_from(int size)(all methods returnresult<T, string>when they can fail)
env exposes operating-system environment access with explicit errors.
env.get(string name) -> optional<string>
data.json is the JSON utility layer built on std.json.
data.json.parse(string json) -> result<Json, string>data.json.from_map(map<string, T>) -> result<Json, string>data.json.to_map(Json value) -> result<map<string, Json>, string>
data.csv parses CSV text into structured rows.
data.csv.parse(string csv_text) -> result<Csv, string>data.csv.parse_with_headers(string csv_text) -> result<Csv, string>
sql provides database connectivity and typed SQL values.
sql.connect(string uri) -> result<Connection, string>Connection.close() -> voidConnection.execute(string sql) -> result<int, string>Connection.execute_params(string sql, list<SqlValue> params) -> result<int, string>Connection.query(string sql) -> result<ResultSet, string>Connection.query_params(string sql, list<SqlValue> params) -> result<ResultSet, string>Connection.begin_transaction() -> result<Transaction, string>Transaction.commit() -> result<void, string>Transaction.rollback() -> result<void, string>Transaction.execute(string sql) -> result<int, string>Transaction.query(string sql) -> result<ResultSet, string>ResultSet.rows() -> list<map<string, SqlValue>>ResultSet.next() -> optional<map<string, SqlValue>>ResultSet.columns() -> list<string>
SqlValue constructors:
sql.int(int) -> SqlValuesql.float(float) -> SqlValuesql.bool(bool) -> SqlValuesql.string(string) -> SqlValuesql.bytes(list<int>) -> SqlValuesql.null() -> SqlValue
SqlValue methods:
.is_null() -> bool.as_bool() -> result<bool, string>.as_int() -> result<int, string>.as_float() -> result<float, string>.as_string() -> result<string, string>.as_bytes() -> result<list<int>, string>.to_string() -> string
Current provider support:
- SQLite: supported (
sqlite::memory:,sqlite:///path/to/file.db) - PostgreSQL: supported (
postgres://...,postgresql://...) - MySQL/MariaDB: supported (
mysql://...,mariadb://...) - SQL Server: URI recognized, currently unsupported
dsa provides data structures and algorithms: stack, queue, heap, bintree, graph, and utility functions.
Import styles:
import std.dsa // use dsa.stack, dsa.queue, etc.
import std.dsa.stack // use stack.*
import std.dsa.algorithm // use algorithm.*
import std.dsa.collection.Collection // import the interface
The Collection<T> interface is implemented by all DSA data structures:
| Method | Returns | Description |
|---|---|---|
len() returns int |
Number of elements | |
is_empty() returns bool |
True if empty | |
clear() returns void |
Remove all elements | |
to_list() returns list<T> |
Elements as a list |
A LIFO (last-in, first-out) collection.
| Method | Returns | Description |
|---|---|---|
Stack<T>.new() returns Stack<T> |
Create empty stack | |
push(T value) returns void |
Add element to top | |
pop() returns optional<T> |
Remove and return top element | |
peek() returns optional<T> |
View top element without removing |
Also implements len(), is_empty(), clear(), to_list().
A FIFO (first-in, first-out) collection.
| Method | Returns | Description |
|---|---|---|
Queue<T>.new() returns Queue<T> |
Create empty queue | |
enqueue(T value) returns void |
Add element to back | |
dequeue() returns optional<T> |
Remove and return front element | |
peek() returns optional<T> |
View front element without removing |
Also implements len(), is_empty(), clear(), to_list().
A min-heap collection where the smallest element is always at the top.
| Method | Returns | Description |
|---|---|---|
Heap<T>.new() returns Heap<T> |
Create empty heap | |
push(T value) returns void |
Add element | |
pop() returns optional<T> |
Remove and return minimum | |
peek() returns optional<T> |
View minimum without removing |
Also implements len(), is_empty(), clear(), to_list().
A binary search tree with set semantics (duplicates ignored).
| Method | Returns | Description |
|---|---|---|
BinaryTree<T>.new() returns BinaryTree<T> |
Create empty tree | |
insert(T value) returns void |
Add element | |
remove(T value) returns void |
Remove element | |
contains(T value) returns bool |
Check if element exists |
Also implements len(), is_empty(), clear(), to_list() (inorder traversal).
A directed graph using adjacency lists.
| Method | Returns | Description |
|---|---|---|
Graph<T>.new() returns Graph<T> |
Create empty graph | |
add_vertex(T value) returns void |
Add a vertex | |
add_edge(T from, T to) returns void |
Add directed edge | |
neighbors(T value) returns list<T> |
Get neighbors of vertex | |
bfs(T start) returns list<T> |
Breadth-first search traversal |
Also implements len(), is_empty(), clear(), to_list() (vertices in insertion order).
| Function | Signature | Description |
|---|---|---|
sort |
<T is Comparable>(list<T> items) returns list<T> |
Quicksort |
binary_search |
<T is Comparable, E is Collection<T>>(E items, T target) returns int |
Returns index or -1 |
max |
<T is Comparable & Stringable, E is Collection<T>>(E collection) returns optional<T> |
Maximum element |
min |
<T is Comparable & Stringable, E is Collection<T>>(E collection) returns optional<T> |
Minimum element |
reverse |
<T, E is Collection<T>>(E collection) returns list<T> |
Reversed list |
mux-lang/
├── mux-compiler/
│ ├── src/
│ │ ├── ast/
│ │ │ ├── types.rs
│ │ │ ├── nodes.rs
│ │ │ ├── literals.rs
│ │ │ ├── operators.rs
│ │ │ ├── patterns.rs
│ │ │ ├── error.rs
│ │ │ └── mod.rs
│ │ ├── codegen/
│ │ │ ├── mod.rs
│ │ │ ├── expressions.rs
│ │ │ ├── statements.rs
│ │ │ ├── functions.rs
│ │ │ ├── methods.rs
│ │ │ ├── classes.rs
│ │ │ ├── constructors.rs
│ │ │ ├── operators.rs
│ │ │ ├── generics.rs
│ │ │ ├── types.rs
│ │ │ ├── memory.rs
│ │ │ └── runtime.rs
│ │ ├── semantics/
│ │ │ ├── mod.rs
│ │ │ ├── types.rs
│ │ │ ├── symbol_table.rs
│ │ │ ├── unifier.rs
│ │ │ ├── format.rs
│ │ │ └── error.rs
│ │ ├── lexer/
│ │ │ ├── mod.rs
│ │ │ ├── token.rs
│ │ │ ├── span.rs
│ │ │ └── error.rs
│ │ ├── parser/
│ │ │ ├── mod.rs
│ │ │ └── error.rs
│ │ ├── diagnostic/
│ │ │ ├── mod.rs
│ │ │ ├── emitter.rs
│ │ │ ├── files.rs
│ │ │ └── styles.rs
│ │ ├── module_resolver.rs
│ │ ├── source.rs
│ │ ├── lib.rs
│ │ └── main.rs
│ └── tests/
│ ├── lexer_integration.rs
│ ├── parser_integration.rs
│ ├── semantics_integration.rs
│ ├── executable_integration.rs
│ └── snapshots/
│
├── mux-runtime/
│ ├── src/
│ │ ├── lib.rs
│ │ ├── object.rs
│ │ ├── refcount.rs
│ │ ├── boxing.rs
│ │ ├── bool.rs
│ │ ├── int.rs
│ │ ├── float.rs
│ │ ├── string.rs
│ │ ├── list.rs
│ │ ├── map.rs
│ │ ├── set.rs
│ │ ├── optional.rs
│ │ ├── result.rs
│ │ ├── io.rs
│ │ ├── math.rs
│ │ └── std.rs
│ └── Cargo.toml
│
├── test_scripts/
│ ├── error_cases/
│ │ ├── *.mux
│ └── *.mux
│
├── Cargo.toml
├── Cargo.lock
└── AGENTS.md
Mux is licensed under the MIT license.
