Initializers
An initializer constructs a new instance of a struct. Kestrel synthesizes one for you by default, but you can write your own when the default isn't enough.
The default memberwise initializer
If you don't write an init, you get one for free that takes one labeled argument per field:
struct Point {
let x: Int
let y: Int
}
let p = Point(x: 0, y: 0);
The memberwise initializer always takes every field — there's no way to skip one. To make a parameter optional, write your own init and give the parameter a default value (defaulted parameters must come after the required ones):
struct Config {
var port: Int
let strict: Bool
init(strict strict: Bool, port port: Int = 8080) {
self.port = port;
self.strict = strict;
}
}
let c = Config(strict: true); // port defaults to 8080
let d = Config(strict: false, port: 9000); // override
Custom initializers
When the default doesn't fit — you want to compute a field, validate input, or pick from multiple inputs — write your own:
struct Span {
let lower: Int
let upper: Int
init(from start: Int, length length: Int) {
self.lower = start;
self.upper = start + length;
}
}
let r = Span(from: 10, length: 5);
Inside init, every let and var field must be assigned before the initializer returns. The compiler checks this — you can't accidentally leave a field uninitialized.
Writing any custom init — even one declared in an extend block — replaces the synthesized memberwise initializer. If you still want memberwise-style construction, declare it yourself alongside the custom one.
Multiple initializers
You can have several inits with different labels — same overloading rules as ordinary functions:
struct Vector {
let x: Float64
let y: Float64
init(x x: Float64, y y: Float64) {
self.x = x;
self.y = y;
}
init(angle angle: Float64, length length: Float64) {
self.x = length * angle.cos();
self.y = length * angle.sin();
}
}
let v = Vector(x: 3.0, y: 4.0);
let u = Vector(angle: 1.57, length: 10.0);
Failable construction
If construction can fail, mark the initializer with ?. A failable init produces an Optional of the type; return null inside it signals failure:
struct User {
let name: String
init(parsing raw: String)? {
if raw.isEmpty {
return null
}
self.name = raw;
}
}
let u = User(parsing: "ada"); // User? — .Some(User(...))
let bad = User(parsing: ""); // .None
This is the same pattern the standard library uses for Int(parsing:) and friends. The failure is visible in the result type, so the call site has to handle it. A static factory method returning Optional or Result works too, when you want a descriptive name or error details.