Structs

Structs are custom data types that group related values together. They’re fundamental to organizing data in Conjure and can contain fields of any type.

Defining Structs

Structs are declared using the struct keyword followed by a name and a block containing field definitions. Fields have a name and type, separated by whitespace.

struct Point2D {
	x f32
	y f32
}

For simple structs, you can define fields on a single line separated by commas.

struct Point2D { x f32, y f32 }

Creating Struct Instances

Create struct instances using construction syntax with field assignments.

var origin = Point2D{ x = 0.0, y = 0.0 }
var point = Point2D{ x = 10.5, y = 20.3 }

When the type is known from context (like a variable declaration with an explicit type), you can omit the struct name.

var unitX Point2D = { x = 1.0, y = 0.0 }

Zero Initialization

Structs can be zero-initialized using empty braces or by simply declaring a variable with the struct type.

var defaultPoint = Point2D{}
var anotherPoint Point2D

Both create a Point2D with x and y set to 0.0.

Accessing Fields

Access struct fields using dot notation.

var p = Point2D{ x = 5.0, y = 10.0 }

io.println("X: #{p.x}")
io.println("Y: #{p.y}")

p.x = 15.0  // modify field

Nested Structs

Structs can contain other structs as fields.

struct Point3D {
	x f32
	y f32
	z f32
}

struct Line3D {
	start Point3D
	end Point3D
}

var line = Line3D{
	start = Point3D{ x = 0.0, y = 0.0, z = 0.0 },
	end = Point3D{ x = 1.0, y = 1.0, z = 1.0 },
}

Anonymous Nested Structs

Structs can contain anonymous nested structs for organizing related data.

struct Node {
	kind u8
	data struct {
		value i32
		binary struct {
			left i32
			right i32
		}
	}
}

Anonymous Unions in Structs

Structs can contain anonymous C-style unions for memory-efficient variant data.

struct Node {
	kind u8
	data union {
		value i32
		binary struct {
			left i32
			right i32
		}
	}
}

Bitfields

Use the @bits attribute to create bitfields for compact data representation. This is useful for packing multiple small values into a single word.

struct PoolRef {
	@bits(4) poolId u8
	@bits(28) index u32
}

Generic Structs

Structs support template parameters for generic programming. Template parameters are specified in square brackets after the struct name.

struct Pair[T1, T2] {
	first T1
	second T2
}

var intStringPair = Pair[i32, string]{ first = 42, second = "hello" }
var floatBoolPair = Pair[f32, bool]{ first = 3.14, second = true }

Struct Attributes

@packed Proposed

The @packed attribute removes padding between fields, creating a tightly packed struct.

@packed struct PackedData {
	a u8
	b u32
	c u8
}

@align Proposed

The @align attribute specifies custom alignment for a struct.

@align(16) struct AlignedData {
	values [4]f32
}

Passing Structs to Functions

Structs are passed by value, meaning the function receives a copy. For large structs, use pointers to avoid expensive copies.

// Passed by value (copy)
func movePoint(p Point2D, dx f32, dy f32) Point2D {
	return Point2D{ x = p.x + dx, y = p.y + dy }
}

// Passed by pointer (no copy)
func movePointInPlace(p *Point2D, dx f32, dy f32) {
	p.x = p.x + dx
	p.y = p.y + dy
}

Returning Structs

Functions can return structs directly.

func createPoint(x f32, y f32) Point2D {
	return Point2D{ x = x, y = y }
}

var p = createPoint(10.0, 20.0)

Struct Methods Proposed

Methods can be associated with structs using Uniform Function Call Syntax (UFCS). A function whose first parameter is the struct type can be called using method syntax.

func length(p Point2D) f32 {
	return math.sqrt(p.x * p.x + p.y * p.y)
}

var point = Point2D{ x = 3.0, y = 4.0 }
var len = point.length()  // UFCS: same as length(point)

Structs with Arrays

Structs can contain fixed-size arrays.

struct Matrix3x3 {
	data [9]f32
}

struct Vertex {
	position [3]f32
	normal [3]f32
	texcoord [2]f32
}

Memory Layout

Structs are laid out in memory with fields in declaration order. The compiler may add padding between fields for alignment unless @packed is used.

struct Example {
	a u8    // 1 byte
	        // 3 bytes padding (for alignment)
	b i32   // 4 bytes
	c u8    // 1 byte
	        // 3 bytes padding
}
// Total size: 12 bytes

@packed struct PackedExample {
	a u8    // 1 byte
	b i32   // 4 bytes
	c u8    // 1 byte
}
// Total size: 6 bytes

Common Patterns

Builder Pattern

struct WindowConfig {
	width i32
	height i32
	title string
	fullscreen bool
	vsync bool
}

var config = WindowConfig{
	width = 1920,
	height = 1080,
	title = "My Game",
	fullscreen = false,
	vsync = true,
}

Data Transfer Objects

struct PlayerData {
	id u64
	name string
	score i32
	position Point3D
}