For the complete Mojo documentation index, see llms.txt. Markdown versions of all pages are available by appending .md to any URL (e.g. /docs/manual/basics.md).
Initialization state
Mojo tracks two kinds of initialization for structs: fieldwise and logical.
Fieldwise initialization means every field contains a valid value. Logical initialization means the instance as a whole is valid and ready to use. A struct needs both before you can use it.
The basics
You create struct instances by calling the __init__() initializer:
struct Person:
var name: String
var age: Int
def __init__(out self, name: String, age: Int):
self.name = name
self.age = age
def main():
var me = Person("Alice", 30)
Calling Person("Alice", 30) is syntactic sugar for calling the
initializer directly:
var me: Person
me = Person.__init__("Alice", 30) # Identical
When constructing a Person, the compiler allocates the
necessary storage and __init__() initializes that memory.
Fieldwise vs logical initialization
Initializing a struct by assigning values directly to its fields may populate the data, but it doesn't make the instance usable:
@fieldwise_init
struct Person(Writable):
var name: String
var age: Int
def main():
var me: Person
me.name = "Alice"
me.age = 25
print(me) # Error
# error: 'me' used with all fields manually initialized
# but without calling an '__init__' method
In this example, all fields contain valid values, but the instance is still not considered initialized.
Assigning every field satisfies fieldwise initialization, but without
running an __init__() method, it doesn't satisfy logical initialization.
Construct the value with an initializer to establish both:
var me: Person # Not initialized
me = Person("Alice", 30) # Logically and fieldwise initialized after call
print(me)
After __init__() completes, the instance is safe to use.
Inside __init__()
Within __init__(), self is logically initialized, but its fields are
uninitialized. This reverses the situation before calling __init__(),
where the fields are initialized but self is not:
def __init__(out self, name: String, age: Int):
# At this point:
# - Logically initialized (self is valid as an instance)
# - Fieldwise uninitialized (fields have no values yet)
self.name = name
self.age = age
# Now both logically and fieldwise initialized
Entering __init__() establishes the instance. It's your responsibility to
populate every field:
def __init__(out self, name: String, age: Int):
self.name = name
# Error: field 'age' not initialized in __init__
The __init__() signature doesn't have to mirror the struct's fields.
You can use parameters, constants, or external values to initialize them:
# Parameters can be used to initialize fields
self._store = List[T](capacity=Count)
# Constants can be used to initialize fields
self.string = ""
# External values can be used to initialize fields
from std.math import pi
self.default_angle = pi / 2.0
self.uuid = MyUUIDImplementation.uuid()
Calling methods
You can't call methods until all fields are initialized:
def __init__(out self, name: String):
self.greet() # Error: self not fully initialized
self.name = name
self.greet() # OK: all fields initialized
Field initialization is limited to __init__() methods.
Regular methods can't initialize individual fields of an out argument,
but __init__() methods can.