Structs Arrive in Luma - Phase 1 is Here Elegance
Luma continues to evolve, and today we’re excited to introduce one of the most requested language features: structs.
This is the foundation for building richer data models, larger programs, and ultimately unlocking higher-level abstractions such as methods, impl blocks, and traits.
Structs are now fully supported in Luma as plain data containers, and they already integrate cleanly with the rest of the language: lists, maps, functions, optionals, and composite data structures.
This post explains:
- What’s implemented today
- What works with structs
- What does not work yet
- What’s coming next in the roadmap
Let’s dive in.
Structs: Phase 1 - What’s Available Today
Phase 1 focuses on data-only structs, with positional construction and field access.
Declaring a struct
struct Person {
name: str
age: int
}This compiles to a Go type:
type Person struct {
name string
age int
}Constructing a struct (positional)
alice: Person = Person("Alice", 25)Luma compiles this to a Go composite literal:
var alice Person = Person{"Alice", 25}Accessing fields
print(alice.name)
print(alice.age)Structs in Functions
fn birthday(p: Person) -> Person {
return Person(p.name, p.age + 1)
}
alice: Person = Person("Alice", 25)
older: Person = birthday(alice)
print(older.age)Structs in Lists
Yes - lists of structs work exactly as expected:
people: [Person] = [
Person("Alice", 25),
Person("Bob", 30),
]
print(people[0].name)Structs in Maps
people_by_name: {str: Person} = {
"Alice": Person("Alice", 25),
"Bob": Person("Bob", 30),
}
print(people_by_name["Alice"].age)Nested Structs
struct Address {
city: str
}
struct Person {
name: str
age: int
address: Address
}
alice: Person = Person("Alice", 25, Address("Tallinn"))
print(alice.address.city)Optional Structs (?Person)
You can store structs inside optional types:
best_friend: ?Person = Person("Alice", 25)
no_friend: ?Person = nilCompilation lowers this cleanly to pointer types (*Person).
Field access still requires a non-optional:
(We’ll add smarter auto-deref rules in the future.)
Not Implemented Yet (By Design)
The following features are explicitly out of scope for Phase 1 and coming later:
Named struct literals
This will NOT work yet:
Person {
name: "Alice",
age: 25
}Positional construction is currently required.
Field mutation
alice.age = 30 // not supported yetMethods / impl blocks
impl Person {
fn greet() -> str { ... }
}Coming soon in Phase 2.
Traits + trait implementations
trait Greeter { ... }
impl Greeter for Person { ... }Phase 3.
Struct Roadmap - What’s Coming Next
Now that structs work cleanly across the whole compiler pipeline, here’s what’s next.
Phase 1.5 - Named Struct Literals
Add support for:
Person { name: "Alice", age: 25 }This requires a new AST node and disambiguation from {map: literals}.
Phase 2 - impl Blocks + Methods
Enable struct-associated functions:
impl Person {
fn greet(self) -> str {
return "Hello, ${self.name}!"
}
}Methods will lower to Go methods or helper functions.
Phase 3 - Traits + Interfaces
trait Greetable {
fn greet() -> str
}
impl Greetable for Person {
fn greet() -> str { ... }
}
fn sayHello(x: Greetable) { ... }Traits will map directly to Go interfaces.
Phase 4 - Named Field Mutation
alice.age = 30This requires type-safe mutation and updated codegen.
Phase 5 - Named Struct Update Syntax
Possibly:
alice2 = Person { ...alice, age: alice.age + 1 }(Likely a later convenience feature.)
Phase 6 - Struct Generics
This unlocks expressive, reusable types:
struct Box[T] {
value: T
}Summary
Structs are now a first-class citizen in Luma:
- Struct declaration
- Positional construction
- Field access
- Lists, maps, nested structs
- Functions and return types
- Optional structs
- Clean Go codegen and stable semantics
You can already build real data models in Luma today - and this foundation sets the stage for methods, traits, and beyond.
If you’re building with Luma or experimenting with the new struct system, share your examples and ideas - we’re just getting started.