Mojo Structs

A struct bundles related data and the functions that operate on that data into one named unit. Instead of tracking a person's name, age, and email in three separate variables, you define a Person struct and store everything together. Mojo structs are the primary way to create custom data types.

The Blueprint Analogy

  Struct Definition (Blueprint)
  ┌────────────────────────────────┐
  │  struct Car:                   │
  │    var make: String            │
  │    var model: String           │
  │    var year: Int               │
  └────────────────────────────────┘
         │           │           │
         ▼           ▼           ▼
   Car instance   Car instance   Car instance
   make="Toyota"  make="Ford"   make="BMW"
   model="Corolla" model="Focus" model="X5"
   year=2022      year=2019     year=2024

  One blueprint → unlimited instances

Defining a Struct

struct Point:
    var x: Float64
    var y: Float64

    fn __init__(inout self, x: Float64, y: Float64):
        self.x = x
        self.y = y

Key Parts

struct Point:                          ← struct keyword + name
    var x: Float64                     ← field (member variable)
    var y: Float64                     ← field

    fn __init__(inout self, x, y):     ← initializer
        self.x = x                     ← store argument into field
        self.y = y

The __init__ method runs automatically when you create a new instance. The self parameter refers to the specific instance being created — it is how the function knows which object's fields to fill.

Creating Instances

fn main():
    var origin = Point(0.0, 0.0)
    var corner = Point(5.0, 3.0)

    print(origin.x, origin.y)   # 0.0 0.0
    print(corner.x, corner.y)   # 5.0 3.0

A Practical Struct: BankAccount

struct BankAccount:
    var owner: String
    var balance: Float64

    fn __init__(inout self, owner: String, opening_balance: Float64):
        self.owner = owner
        self.balance = opening_balance

    fn deposit(inout self, amount: Float64):
        self.balance += amount
        print(self.owner, "deposited", amount, "| Balance:", self.balance)

    fn withdraw(inout self, amount: Float64):
        if amount > self.balance:
            print("Insufficient funds")
        else:
            self.balance -= amount
            print(self.owner, "withdrew", amount, "| Balance:", self.balance)

    fn show_balance(self):
        print(self.owner, "balance:", self.balance)

fn main():
    var acc = BankAccount("Aisha", 1000.0)
    acc.deposit(500.0)      # Aisha deposited 500.0 | Balance: 1500.0
    acc.withdraw(200.0)     # Aisha withdrew 200.0  | Balance: 1300.0
    acc.withdraw(2000.0)    # Insufficient funds
    acc.show_balance()      # Aisha balance: 1300.0

The self Parameter

Every method inside a struct receives self as its first parameter. self is the current instance — it lets the method access and modify that specific instance's fields.

  acc.deposit(500.0)
   │         │
   │         └── argument 'amount'
   └── becomes 'self' inside the method

  Inside deposit:
    self.balance += amount
    ↑                ↑
    acc's balance    500.0

When a method only reads fields, use fn method(self):. When a method modifies fields, use fn method(inout self):.

Struct Memory Layout

  struct Point:          Memory layout for Point(3.0, 7.0):
    var x: Float64   →   [  3.0  ][  7.0  ]
    var y: Float64       8 bytes   8 bytes
                         total: 16 bytes on stack

  Structs in Mojo store data on the stack by default —
  no pointer indirection, no garbage collection overhead.

Immutable vs Mutable Methods

struct Temperature:
    var celsius: Float64

    fn __init__(inout self, c: Float64):
        self.celsius = c

    # Read-only — does not modify the struct
    fn to_fahrenheit(self) -> Float64:
        return self.celsius * 9.0 / 5.0 + 32.0

    # Mutating — changes the struct's field
    fn set(inout self, c: Float64):
        self.celsius = c

fn main():
    var temp = Temperature(100.0)
    print(temp.to_fahrenheit())   # 212.0
    temp.set(0.0)
    print(temp.to_fahrenheit())   # 32.0

Structs vs Python Classes

Feature                  | Mojo Struct         | Python Class
-------------------------|---------------------|------------------
Memory layout            | Fixed, on stack     | Heap, dynamic
Field types              | Must be declared    | No types required
Performance              | C-level speed       | Interpreted speed
Inheritance              | Via Traits          | Direct
Dynamic attributes       | Not supported       | Supported

Key Takeaways

A struct groups related fields and methods into one custom type. The __init__ method initializes the struct when you create an instance. Use self to access the current instance's fields. Read-only methods use self; mutating methods use inout self. Mojo structs store data on the stack, giving them C-level performance with Python-like readability.

Leave a Comment

Your email address will not be published. Required fields are marked *