Skip to main content

@fieldwise_init

You can add the @fieldwise_init decorator on a struct to generate the field-wise __init__() constructor.

For example, consider a simple struct like this:

@fieldwise_init
struct MyPet:
    var name: String
    var age: Int

Mojo sees the @fieldwise_init decorator and synthesizes a field-wise constructor, the result being as if you had actually written this:

struct MyPet:
    var name: String
    var age: Int

    fn __init__(out self, var name: String, age: Int):
        self.name = name^
        self.age = age

You can synthesize the copy constructor and move constructor by adding the Copyable trait to your struct. For more information about these lifecycle methods, read Life of a value.

Implicit conversionโ€‹

Implicit conversion lets you pass a value and lets a type build itself, without calling the constructor directly. This keeps caller code simple and clean. You enable this by marking an initializer as @implicit or using @fieldwise_init("implicit") to create one for you.

For example, if MyStruct has an initializer that accepts an Int, you can construct an instance like this:

an_instance = MyStruct(42)

A function that takes a MyStruct will accept that instance, an explicit constructor call, or the value that can be converted into one:

some_function(an_instance)      # pass an instance
some_function(MyStruct(42))     # build one directly
some_function(42)               # implicit conversion

All three forms create a MyStruct for the call. Some may have small compile-time or run-time differences.

Declaring implicit initializationโ€‹

You can declare implicit initializers in two ways:

  • Use @fieldwise_init("implicit") to auto-create one, as long as your type has exactly one instance field. This limit applies to the type itself, not just to initializer arguments.
  • Add @implicit to an initializer you write. The initializer can accept only one argument.

Fieldwise and implicit exampleโ€‹

Here is a type that stores an Int. It can be created with an integer or from any value that can be floored and converted to an integer. It uses @fieldwise_init("implicit") for integers and creates an @implicit initializer for other values:

from math import Floorable, floor

# Creates an implicit initializer and limits the type to one instance field.
@fieldwise_init("implicit")
struct FlooringInt:
    var floored: Int

    # Allows implicit conversion from types that can be floored and made into an Int.
    @implicit
    fn __init__[T: Floorable & Intable](out self, value: T):
        self.floored = Int(floor(value))

fn floored(value: FlooringInt) -> Int:
    return value.floored

fn main():
    print(floored(FlooringInt(42)))  # pass an instance, output: 42
    print(floored(2))                # pass Int, output: 2
    print(floored(52.6))             # pass Float64, output: 52
    x = BFloat16(192.3)
    print(floored(x))                # pass BFloat16, output: 192
    y: FlooringInt = 180
    print(y.floored)                 # output 180
    z: FlooringInt = 3.14159
    print(z.floored)                 # output: 3

What you don't see in this example is an initializer for integers. Adding @fieldwise_init("implicit") lets the compiler build it for you. If you wrote this by hand, it might look like this:

@implicit
fn __init__(out self, floored: Int):
    self.floored = floored

Was this page helpful?