/

Examples

Playground Docs Architecture Extensions Concurrency Home GitHub

Core

Variables, functions, closures, control flow, and pattern matching — the building blocks of every Lattice program.

// Variables — flux is mutable, fix is immutable flux x = 10 x = x + 5 print(x) // 15 fix name = "Lattice" print(name) // Lattice
// Functions fn greet(name: String) -> String { return "Hello, ${name}!" } print(greet("world")) // Hello, world! fn add(a: Int, b: Int) -> Int { return a + b } print(add(3, 4)) // 7
// Closures fix double = |x: Int| { x * 2 } print(double(21)) // 42 fn make_adder(n: Int) -> Fn { return |x: Int| { x + n } } fix add5 = make_adder(5) print(add5(10)) // 15
// Control flow flux x = 42 if x > 10 { print("big") } else { print("small") } // Ternary-style fix label = if x > 100 { "huge" } else { "normal" } print(label) // normal
// Pattern matching fn describe(val: any) -> String { match val { 0 => "zero", n if n > 0 => "positive", _ => "negative" } } print(describe(5)) // positive print(describe(0)) // zero print(describe(-3)) // negative
// While loop flux count = 0 while count < 5 { count = count + 1 } print(count) // 5
// For loop for i in 0..5 { print(i) } // For-each over a collection fix names = ["Alice", "Bob", "Carol"] for name in names { print("Hello, ${name}!") }
// Try / catch try { fix result = 10 / 0 } catch e { print("Error: ${e}") }

Phase System

Lattice's phase system gives you fine-grained control over mutability. flux declares mutable values, fix declares immutable values, and let infers the phase. Use freeze(), thaw(), and clone() for phase transitions.

// Mutable (flux) variables can be reassigned flux data = [1, 2, 3] data.push(4) print(data) // [1, 2, 3, 4] // Freeze to make immutable fix frozen = freeze(data) // frozen.push(5) // ERROR: cannot mutate crystal value print(frozen) // [1, 2, 3, 4]
// Thaw to make mutable again flux thawed = thaw(frozen) thawed.push(5) print(thawed) // [1, 2, 3, 4, 5]
// Clone preserves phase fix original = freeze([1, 2, 3]) fix copy = clone(original) print(copy) // [1, 2, 3]
// let infers the phase from usage let x = 42 print(x) // 42 // Phase-aware function parameters fn process(items: Array) -> Array { flux result = clone(items) result.push(99) return freeze(result) } fix out = process([1, 2, 3]) print(out) // [1, 2, 3, 99]
// Freeze maps too flux config = Map::new() config["host"] = "localhost" config["port"] = 8080 fix locked = freeze(config) print(locked["host"]) // localhost // locked["port"] = 9090 // ERROR: cannot mutate crystal value

Structs & Enums

Define custom data types with struct and algebraic data types with enum. Methods are attached using standalone functions with typed self parameters.

// Struct definition and instantiation struct Point { x, y } flux p = Point { x: 3, y: 4 } print("${p.x}, ${p.y}") // 3, 4
// Methods via impl-style functions fn Point.distance(self: Point) -> Float { Math.sqrt(self.x * self.x + self.y * self.y) } fix p = Point { x: 3, y: 4 } print(p.distance()) // 5.0
// Struct with more fields struct Person { name, age, email } fix alice = Person { name: "Alice", age: 30, email: "alice@example.com" } print("${alice.name} is ${alice.age}") // Alice is 30
// Enum with variants enum Shape { Circle(Float), Rectangle(Float, Float) } flux s = Shape::Circle(5.0) match s { Shape::Circle(r) => print("circle r=${r}"), Shape::Rectangle(w, h) => print("rect ${w}x${h}") }
// Enum methods fn Shape.area(self: Shape) -> Float { match self { Shape::Circle(r) => Math.pi() * r * r, Shape::Rectangle(w, h) => w * h } } fix circle = Shape::Circle(5.0) print(circle.area()) // 78.5398... fix rect = Shape::Rectangle(4.0, 6.0) print(rect.area()) // 24.0
// Simple enums (no payloads) enum Color { Red, Green, Blue } fix c = Color::Green match c { Color::Red => print("red"), Color::Green => print("green"), Color::Blue => print("blue") }
// Enum variant_name / .tag() fix s = Shape::Circle(3.0) print(s.tag()) // Circle

Math

The Math module provides common mathematical functions, constants, and random number generation.

// Basic math functions print(Math.sqrt(144)) // 12.0 print(Math.pow(2, 10)) // 1024.0 print(Math.abs(-42)) // 42 print(Math.floor(3.7)) // 3 print(Math.ceil(3.2)) // 4 print(Math.round(3.5)) // 4
// Min, max, clamp print(Math.min(5, 3)) // 3 print(Math.max(5, 3)) // 5
// Constants print(Math.pi()) // 3.14159... print(Math.e()) // 2.71828... print(Math.random()) // 0.0..1.0
// Trigonometry print(Math.sin(Math.pi() / 2)) // 1.0 print(Math.cos(0)) // 1.0 print(Math.tan(0)) // 0.0 print(Math.atan2(1, 1)) // 0.7853...
// Logarithms print(Math.log(Math.e())) // 1.0 print(Math.log2(8)) // 3.0 print(Math.log10(100)) // 2.0

Strings

String methods for manipulation, searching, splitting, and formatting. Lattice strings support ${expr} interpolation.

fix s = "Hello, World!" print(s.len()) // 13 print(s.to_upper()) // HELLO, WORLD! print(s.to_lower()) // hello, world!
// Searching fix s = "Hello, World!" print(s.contains("World")) // true print(s.starts_with("Hello")) // true print(s.ends_with("!")) // true
// Replace, split, trim fix s = "Hello, World!" print(s.replace("World", "Lattice")) // Hello, Lattice! print(s.split(", ")) // ["Hello", "World!"] print(" hello ".trim()) // hello
// Characters and reversing fix s = "Hello" print(s.chars()) // ["H", "e", "l", "l", "o"] print(s.reverse()) // olleH
// String interpolation flux name = "Lattice" fix version = 3 print("Welcome to ${name} v${version}!") // Welcome to Lattice v3!
// Substring and repeat fix s = "Hello, World!" print(s.substring(0, 5)) // Hello print(s.repeat(2)) // Hello, World!Hello, World!
// Padding print("42".pad_left(6, "0")) // 000042 print("hi".pad_right(6, ".")) // hi....

Arrays

Dynamic arrays with push, pop, functional transformations, sorting, and slicing.

// Creating and modifying arrays flux arr = [3, 1, 4, 1, 5, 9] arr.push(2) print(arr.len()) // 7 print(arr.contains(4)) // true
// Functional operations fix arr = [3, 1, 4, 1, 5, 9] fix doubled = arr.map(|x: Int| { x * 2 }) print(doubled) // [6, 2, 8, 2, 10, 18] fix evens = arr.filter(|x: Int| { x % 2 == 0 }) print(evens) // [4] fix sum = arr.reduce(0, |acc: Int, x: Int| { acc + x }) print(sum) // 23
// Sorting fix arr = [3, 1, 4, 1, 5, 9] fix sorted = arr.sort() print(sorted) // [1, 1, 3, 4, 5, 9]
// Slicing and indexing fix arr = [10, 20, 30, 40, 50] print(arr.slice(1, 4)) // [20, 30, 40] print(arr.first()) // 10 print(arr.last()) // 50
// Reverse, unique, flatten fix arr = [1, 2, 2, 3, 3, 3] print(arr.reverse()) // [3, 3, 3, 2, 2, 1] print(arr.unique()) // [1, 2, 3] fix nested = [[1, 2], [3, 4], [5]] print(nested.flatten()) // [1, 2, 3, 4, 5]
// Zip two arrays fix names = ["Alice", "Bob", "Carol"] fix ages = [30, 25, 28] fix pairs = names.zip(ages) print(pairs) // [["Alice", 30], ["Bob", 25], ["Carol", 28]]
// Chaining functional operations fix result = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10] .filter(|x: Int| { x % 2 == 0 }) .map(|x: Int| { x * x }) .reduce(0, |a: Int, b: Int| { a + b }) print(result) // 220

Maps

Key-value maps created with Map::new() and mutated via index assignment. Maps are pass-by-value in Lattice.

// Creating and populating a map flux m = Map::new() m["name"] = "Alice" m["age"] = 30 print(m["name"]) // Alice print(m.len()) // 2
// Keys, values, entries flux m = Map::new() m["name"] = "Alice" m["age"] = 30 print(m.keys()) // ["name", "age"] print(m.values()) // ["Alice", 30] print(m.has("name")) // true print(m.entries()) // [["name","Alice"],["age",30]]
// Iteration over entries flux m = Map::new() m["x"] = 10 m["y"] = 20 for entry in m.entries() { print("${entry[0]}: ${entry[1]}") } // x: 10 // y: 20
// Merge two maps flux a = Map::new() a["name"] = "Alice" a["age"] = 30 flux b = Map::new() b["city"] = "NYC" fix merged = a.merge(b) print(merged.keys()) // ["name", "age", "city"]
// Remove a key flux m = Map::new() m["a"] = 1 m["b"] = 2 m["c"] = 3 m.remove("b") print(m.keys()) // ["a", "c"] print(m.len()) // 2

Sets

Unordered collections of unique values with union, intersection, and difference operations.

// Creating a set flux s = Set::new() s.add(1) s.add(2) s.add(3) s.add(2) // duplicate ignored print(s.len()) // 3 print(s.has(2)) // true print(s.to_array()) // [1, 2, 3]
// Set operations flux a = Set::new() a.add(1) a.add(2) a.add(3) flux b = Set::new() b.add(2) b.add(3) b.add(4) print(a.union(b)) // {1, 2, 3, 4} print(a.intersection(b)) // {2, 3} print(a.difference(b)) // {1}
// Remove from set flux s = Set::new() s.add("apple") s.add("banana") s.add("cherry") s.remove("banana") print(s.has("banana")) // false print(s.len()) // 2

File System

Read, write, and manage files and directories with the Fs module.

// Read and write files Fs.write("hello.txt", "Hello, World!") fix content = Fs.read("hello.txt") print(content) // Hello, World!
// Append to a file Fs.append("hello.txt", "\nGoodbye!") fix content = Fs.read("hello.txt") print(content) // Hello, World! // Goodbye!
// Check existence print(Fs.exists("hello.txt")) // true print(Fs.exists("nope.txt")) // false
// Directory operations Fs.mkdir("my_dir") fix files = Fs.readdir(".") for f in files { print(f) }
// File info fix info = Fs.stat("hello.txt") print(info["size"])
// Remove files Fs.remove("hello.txt") print(Fs.exists("hello.txt")) // false

JSON / TOML / YAML

Encode and decode structured data with Json, Toml, and Yaml modules.

// JSON encode and decode flux data = Map::new() data["name"] = "Alice" data["scores"] = [95, 87, 92] fix json_str = Json.encode(data) print(json_str) // {"name":"Alice","scores":[95,87,92]} fix parsed = Json.decode(json_str) print(parsed["name"]) // Alice
// TOML flux config = Map::new() config["host"] = "localhost" config["port"] = 8080 fix toml_str = Toml.encode(config) fix from_toml = Toml.decode(toml_str) print(from_toml["host"]) // localhost
// YAML flux data = Map::new() data["title"] = "My App" data["version"] = 1 fix yaml_str = Yaml.encode(data) fix from_yaml = Yaml.decode(yaml_str) print(from_yaml["title"]) // My App
// Read JSON from file Fs.write("data.json", "{\"count\": 42}") fix raw = Fs.read("data.json") fix obj = Json.decode(raw) print(obj["count"]) // 42

HTTP

Make HTTP requests with the Http module. Supports GET, POST, and custom headers.

// GET request fix resp = Http.get("https://api.example.com/data") print(resp["status"]) // 200 print(resp["body"])
// POST with JSON body flux payload = Map::new() payload["username"] = "alice" payload["action"] = "login" flux headers = Map::new() headers["Content-Type"] = "application/json" fix body = Json.encode(payload) fix resp = Http.post("https://api.example.com/login", body, headers) print(resp["status"])
// Response handling fix resp = Http.get("https://api.example.com/users") if resp["status"] == 200 { fix data = Json.decode(resp["body"]) print(data) } else { print("Error: ${resp[\"status\"]}") }

TCP / TLS

Low-level networking with Tcp and Tls modules for socket communication.

// TCP server fix server = Tcp.listen("0.0.0.0", 8080) fix conn = server.accept() fix data = conn.read() conn.write("Echo: ${data}") conn.close()
// TCP client fix client = Tcp.connect("localhost", 8080) client.write("Hello!") fix response = client.read() print(response) // Echo: Hello! client.close()
// TLS client fix tls = Tls.connect("example.com", 443) tls.write("GET / HTTP/1.1\r\nHost: example.com\r\n\r\n") fix resp = tls.read() print(resp) tls.close()

Crypto

Hashing, HMAC, random bytes, and base64 encoding with the Crypto module.

// Hashing fix hash = Crypto.sha256("hello") print(hash) // 2cf24dba5fb0a30e... fix md5 = Crypto.md5("hello") print(md5) // 5d41402abc4b2a76...
// HMAC fix hmac = Crypto.hmac_sha256("key", "message") print(hmac)
// Random bytes fix bytes = Crypto.random_bytes(32) print(bytes.len()) // 32
// Base64 encode and decode fix encoded = Crypto.base64_encode("Hello!") print(encoded) // SGVsbG8h fix decoded = Crypto.base64_decode(encoded) print(decoded) // Hello!

Environment

Access environment variables, command-line arguments, and execute system processes.

// Environment variables fix home = Env.get("HOME") print(home) Env.set("MY_VAR", "hello") print(Env.get("MY_VAR")) // hello
// Command line arguments fix args = Process.args() for arg in args { print(arg) }
// Process execution fix result = Process.exec("echo", ["hello", "world"]) print(result["stdout"]) // hello world print(result["status"]) // 0
// Exit the process // Process.exit(0) // Process.exit(1) // non-zero for errors

DateTime

Date and time operations with the DateTime module.

// Current date and time fix now = DateTime.now() print(now)
// Unix timestamp fix ts = DateTime.timestamp() print(ts) // e.g., 1708876800
// Formatting fix now = DateTime.now() fix formatted = DateTime.format(now, "%Y-%m-%d %H:%M:%S") print(formatted) // 2024-01-15 14:30:00
// Parsing a date string fix parsed = DateTime.parse("2024-01-15", "%Y-%m-%d") print(parsed)

Regex

Regular expression matching, searching, and replacement with the Regex module.

// Match check fix pattern = Regex.new("\\d+") print(Regex.is_match(pattern, "abc123")) // true print(Regex.is_match(pattern, "abcdef")) // false
// Find all matches fix pattern = Regex.new("\\d+") fix matches = Regex.find_all(pattern, "foo42bar99baz7") print(matches) // ["42", "99", "7"]
// Replace matches fix pattern = Regex.new("\\d+") fix replaced = Regex.replace(pattern, "foo42bar99", "XX") print(replaced) // fooXXbarXX
// Email validation pattern fix email_re = Regex.new("^[^@]+@[^@]+\\.[^@]+$") print(Regex.is_match(email_re, "user@example.com")) // true print(Regex.is_match(email_re, "not-an-email")) // false

Concurrency

Structured concurrency with scope/spawn, channels for communication, and select for multiplexing.

// Channels and scope/spawn fix ch = Channel::new() scope { spawn { for i in 1..6 { ch.send(freeze(i)) } ch.close() } spawn { flux running = true while running { flux val = ch.recv() if val == nil { running = false } else { print("received: ${val}") } } } }
// Multiple producers, single consumer fix ch = Channel::new() scope { spawn { ch.send(freeze("from A")) } spawn { ch.send(freeze("from B")) } spawn { ch.send(freeze("from C")) } spawn { for i in 0..3 { fix msg = ch.recv() print(msg) } } }
// Select on multiple channels fix ch1 = Channel::new() fix ch2 = Channel::new() scope { spawn { ch1.send(freeze("hello")) } spawn { ch2.send(freeze("world")) } } select { msg from ch1 => print("ch1: ${msg}"), msg from ch2 => print("ch2: ${msg}") }
// Parallel computation with channels fix results = Channel::new() scope { spawn { // Compute something expensive flux sum = 0 for i in 0..1000 { sum = sum + i } results.send(freeze(sum)) } spawn { // Compute something else flux product = 1 for i in 1..11 { product = product * i } results.send(freeze(product)) } spawn { fix a = results.recv() fix b = results.recv() print("Results: ${a}, ${b}") } }
// Pipeline pattern fix input = Channel::new() fix doubled = Channel::new() fix output = Channel::new() scope { // Stage 1: generate numbers spawn { for i in 1..6 { input.send(freeze(i)) } input.close() } // Stage 2: double each value spawn { flux running = true while running { flux val = input.recv() if val == nil { running = false } else { doubled.send(freeze(val * 2)) } } doubled.close() } // Stage 3: print results spawn { flux running = true while running { flux val = doubled.recv() if val == nil { running = false } else { print(val) } } } } // Output: 2, 4, 6, 8, 10