Structs & OOP
Jda uses a struct + trait + impl model for object-oriented programming, similar to Rust. There are no classes — data (structs) and behavior (functions, traits, impls) are composed together.
Structs
Structs are value types with named fields:
struct Point {
x: i64
y: i64
}
fn main() -> i64 {
let p = Point{}
p.x = 10
p.y = 20
print_i64(p.x + p.y) // prints 30
ret 0
}Struct Pointers
Pass structs by reference for efficiency:
fn move_point(p: &Point, dx: i64, dy: i64) {
p.x = p.x + dx
p.y = p.y + dy
}
fn main() -> i64 {
let p = Point{}
p.x = 5
p.y = 10
move_point(&p, 3, 4)
print_i64(p.x) // prints 8
ret 0
}Nested Structs
struct Rect {
origin: Point
width: i64
height: i64
}
fn area(r: &Rect) -> i64 {
ret r.width * r.height
}Arrays in Structs
struct Buffer {
data: i64[256]
len: i64
}Traits (Interfaces)
Traits define shared behavior:
trait Shape {
fn area(self: &Self) -> i64
}
trait Printable {
fn show(self: &Self)
}Default Methods
Traits can have default implementations:
trait Describable {
fn name(self: &Self) -> i64 // required
fn describe(self: &Self) { // default
print("object")
}
}Impl (Implementation)
Implement traits for structs:
struct Circle { radius: i64 }
impl Shape for Circle {
fn area(self: &Circle) -> i64 {
ret self.radius * self.radius * 3
}
}
impl Printable for Circle {
fn show(self: &Circle) {
print("Circle(r=")
print_i64(self.radius)
print(")")
}
}Derive Macros
Auto-generate common trait implementations:
derive(Debug, Eq, Clone, Hash, Zero, Ord)
struct Config {
width: i64
height: i64
depth: i64
}| Derive | Generates |
|---|---|
Debug | Config_debug(&c) — print struct fields |
Eq | Config_eq(&a, &b) — field-by-field equality |
Clone | Config_clone(&c) — deep copy |
Hash | Config_hash(&c) — hash of all fields |
Zero | Config_zero(&c) — zero all fields |
Ord | Config_lt(&a, &b) — lexicographic ordering |
Generic Structs
struct Pair<T> {
first: T
second: T
}
fn pair_swap<T>(p: &Pair<T>) {
let tmp = p.first
p.first = p.second
p.second = tmp
}OOP Patterns
Encapsulation
Group related functions with a naming convention:
struct Stack {
data: i64[1024]
top: i64
}
fn stack_new() -> Stack {
let s = Stack{}
s.top = 0
ret s
}
fn stack_push(s: &Stack, val: i64) {
s.data[s.top] = val
s.top = s.top + 1
}
fn stack_pop(s: &Stack) -> i64 {
s.top = s.top - 1
ret s.data[s.top]
}Operator Overloading
fn Point_add(a: &Point, b: &Point) -> Point {
let r = Point{}
r.x = a.x + b.x
r.y = a.y + b.y
ret r
}Builder Pattern
fn config_builder() -> Config {
let c = Config{}
c.width = 800
c.height = 600
c.depth = 32
ret c
}