"The language where code becomes poetry" - Topaz syntax pursues maximum expressiveness with minimal code. Master Topaz's beautiful syntax in this comprehensive guide.
Core Philosophy
"Write Less, Express More"
Even complex logic can be expressed concisely and readably.
Global Syntax, Local Expression
- Keywords: Unified in English (
function,let,match,case) - Identifiers: Free use of any language, English, Unicode, and even emojis
Everything is an Expression
All constructs like if, match, for, try return values.
Basic Syntax
Variable Declaration
// Immutable variables (default)
let name = "Alice"
let age = 25
let isActive = true
// Mutable variables
let mut score = 85
score = 90 // Can be changed
// Type annotation (optional)
let distance: float = 3.14
let users: Array<string> = ["John", "Jane"]
Null‑Coalescing Assignment (??=)
Statement‑only operator that initializes when the target is None/null.
let mut name: Option<string> = None
name ??= Some("guest") // now Some("guest")
Function Definition
// Basic function
function greet(name: string) -> string {
"Hello, {name}!"
}
// Default parameters
function calculate(x: int, y: int = 10) -> int {
x + y
}
// Multiple return values
function getCoordinates() -> (int, int) {
(100, 200)
}
// Higher-order functions
function transform(data: Array<int>, fn: (int) -> int) -> Array<int> {
data.map(fn)
}
In type positions, public Topaz docs use the arrow form (T) -> U for function types.
Conditionals
// if expression (returns a value)
let message = if age >= 20 {
"You are an adult"
} else if age >= 13 {
"You are a teenager"
} else {
"You are a child"
}
// Ternary-style
let status = if online { "Connected" } else { "Offline" }
Pattern Matching
// Basic matching
let result = match value {
case 1 => "One"
case 2 => "Two"
case 3 => "Three"
case _ => "Other"
}
// Range matching
let grade = match score {
case 90..100 => "A"
case 80..<90 => "B"
case 70..<80 => "C"
case _ => "F"
}
// Structural matching
let discount = match customer {
case { tier: "VIP", amount } if amount > 1000000 => 0.3
case { tier: "VIP" } => 0.2
case { joinDate } if today - joinDate > 365.days => 0.1
case _ => 0.0
}
#### List Patterns
```topaz
match xs {
case [head, ..tail] => useHead(head, tail)
case [..init, last] => useLast(init, last)
case [a, .., z] => useEnds(a, z)
case [x, y, ..rest] if rest.length > 0 => handle(x, y, rest)
}
End‑to‑end example (guard + nested list pattern):
let desc = match numbers {
case [] => "empty"
case [single] => "single"
case [first, .., last] if first < last => "ascending edge"
case [first, ..mid, last] => "edges {first}..{last}, mid={mid.length}"
}
Pipeline Operations
Basic Pipeline
// Data flows like poetry
let result = rawData
|> normalize()
|> filter(x => x > 0)
|> map(x => x * 2)
|> sort()
Mixed with Method Chaining
let processedString = "hello world"
.split(" ")
|> each(word => word.capitalize())
.join(" ")
|> append("!", _)
// Result: "Hello World!"
Pipe Sugar
v4Use concise sugar on the right side of a pipe:
value
|> .length // property sugar: (x => x.length)
|> replace("foo", _, "bar") // method sugar: (x => replace("foo", x, "bar"))
// Multiple placeholders bind left-to-right within the nearest call
value |> format("id=", _, ":", _)
Type System
Type Inference
// Types are automatically inferred
let number = 42 // int
let text = "hello" // string
let array = [1, 2, 3, 4] // Array<int>
let object = { // { name: string, age: int }
name: "Alice",
age: 25
}
Literal Types
// Restrict types to exact values
type TrafficLight = "red" | "yellow" | "green"
type DiceRoll = 1 | 2 | 3 | 4 | 5 | 6
type StatusCode = 200 | 404 | 500
function handleSignal(color: TrafficLight) {
match color {
case "red" => stop()
case "yellow" => caution()
case "green" => go()
// Compiler ensures all cases are handled!
}
}
Union Types
type UserInput = string | int | null
function process(input: UserInput) -> string {
match input {
case text: string => "String: {text}"
case number: int => "Number: {number}"
case null => "No input"
}
}
null and Option<T> are related but distinct. Use null in nullable unions such as T | null, and use Some(...) / None for Option<T>. Operators like ?? and ?. work across both models.
Loops
for Loops (Expressions)
// Range iteration
for i in 1..10 {
print("Number: {i}")
}
// Array iteration
for item in ["apple", "banana", "cherry"] {
print("Fruit: {item}")
}
// With index
for (index, value) in data.enumerate() {
print("{index}: {value}")
}
// for returns values too!
let squares = for x in 1..5 { x * x } // [1, 4, 9, 16, 25]
Range step with by
v4
// Step forward
for i in 0..10 by 2 { print(i) } // 0,2,4,6,8,10
// Step backward with negative stride
for i in 10..0 by -3 { print(i) } // 10,7,4,1
// Date/Time step (library-defined durations)
for day in startDate..endDate by 1.day { schedule.add(day) }
while Loops
let mut counter = 0
while counter < 10 {
print("Counter: {counter}")
counter = counter + 1
}
Collections
Arrays
// Basic arrays
let numbers = [1, 2, 3, 4, 5]
let fruits = ["apple", "banana", "cherry"]
// Array methods
let large = numbers.filter(x => x > 2) // [3, 4, 5]
let squares = numbers.map(x => x * x) // [1, 4, 9, 16, 25]
let sum = numbers.reduce(0, +) // 15
Membership (in)
// Arrays/Lists/Sets
let ok1 = 3 in [1, 2, 3]
let ok2 = "a" in Set.of("a", "b")
// Map keys
let hasId = "id" in userMap.keys
// Ranges
let inside = 5 in 1..10
let outside = 10 in 1..<10
Objects/Structs
// Object literal
let user = {
name: "Alice",
age: 25,
email: "alice@example.com"
}
// Struct definition
struct User {
name: string,
age: int,
email: string
}
// Struct instance
let newUser = User {
name: "Bob",
age: 30,
email: "bob@example.com"
}
Record Update Literal
v4Shallow‑copy a record and update selected fields immutably.
let user = { name: "Alice", age: 20, city: "Seoul" }
let updated = user{ age: user.age + 1, city: "Busan" }
// { name: "Alice", age: 21, city: "Busan" }
String Templates
Basic Interpolation
let name = "Alice"
let age = 25
let greeting = "Hello, {name}! You are {age} years old."
Tagged Templates
v4Standardized tags with safety and meta preservation:
let path = p"/home/{user}/docs/{fileName}" // path normalization
let pattern = r"^[a-z0-9_]+$" // regex with light escapes
let cmd = sh"grep {pattern} {file}" // safe shell template (execution policy‑controlled)
// SQL: parameters are always bound (no raw string insertion)
let query = sql"SELECT * FROM users WHERE age > {age} AND city = {city}"
Async Processing
Automatic Async
// I/O is automatically async but written like sync!
function getUserInfo(id: int) -> User {
let basicInfo = API.fetchUser(id) // implicit async handling
let profile = API.fetchProfile(id) // implicit async handling
User {
basicInfo: basicInfo,
profile: profile
}
}
Parallel Execution
// Run multiple tasks in parallel
let results = concurrent {
weather: WeatherAPI.current("NYC"),
rate: CurrencyAPI.usdRate(),
news: NewsAPI.headlines(5)
}
Error Handling
Result Type
function safeDivide(a: int, b: int) -> Result<int, string> {
if b == 0 {
Err("Cannot divide by zero")
} else {
Ok(a / b)
}
}
// Simple with ? operator
function complexCalculation(x: int) -> Result<int, string> {
let result1 = safeDivide(x, 2)?
let result2 = safeDivide(result1, 3)?
Ok(result2 * 10)
}
try Expression
let config = try {
readFile("config.json")?
} else {
// Return default value
{ theme: "dark", language: "english" }
}
Advanced Features
Partial Application
let add10 = add(10, _)
let result = [1, 2, 3].map(add10) // [11, 12, 13]
Option‑Safe Optional Chaining (?.)
v4Use ?. only when the left side is Option<T> or a nullable union (e.g., T | null). It desugars to Option.map/flatMap and short‑circuits left‑to‑right.
let user: Option<{ name: string, profile: Option<{ city: string }> }> =
Some({ name: "Ann", profile: Some({ city: "Seoul" }) })
// Each hop returns Option<...>
let nameOpt = user?.name
let cityOpt = user?.profile?.city
// Combine with ?? for defaults
let city = user?.profile?.city ?? "Unknown"
// Not generic object chaining; use `.` for non‑Option values
let plain = { name: "Jo" }
let ok = plain.name // use .
Equivalence with map/flatMap:
// user?.profile?.city
let viaFns = user
|> Option.flatMap(_, u => u.profile)
|> Option.map(_, p => p.city)
Macros
// Repeat execution macro
macro repeatExecution(times: int) {
for i in 1..times {
print("Execution {i}/{times}")
yield // Execute user code
}
}
repeatExecution(3) {
importantTask()
}
Practical Examples
Web API Call
let userData = fetch("https://api.example.com/users/1")
|> json()
|> (data => {
name: data.name,
email: data.email,
joinDate: Date.parse(data.created_at)
})
Data Processing Pipeline
let analysisResult = CSV.read("sales.csv")
|> filter(row => row.revenue > 1000000)
|> groupBy(row => row.region)
|> aggregate(group => {
region: group.key,
totalRevenue: group.values.sum(row => row.revenue),
avgRevenue: group.values.average(row => row.revenue)
})
|> sortBy(descending: row => row.totalRevenue)
Next Steps
You've now mastered Topaz's basic syntax! What to learn next:
- Data Types - Deep dive into the type system
- Functions & Closures - Master functional programming
- Error Handling - Write safe, robust code
Continue your journey where coding becomes poetry with Topaz!