Default auto generated init(): member property with default value must be 'var', cannot be 'let'?

This is what I want: member property to be a let, with default value that can be overridden and make use of compiler auto generated init().

// This is how I want write out: `x` is `let`, with default overridable value
struct Foo {
    let x: Int? = nil
}

let foo = Foo(x: 123)    // **error:** **argument passed to call that takes no arguments**

So I must write out the init:

Struct Foo {
    let x: Int?

    init(x: Int? = nil) {
        self.x = x
    }
}

Or change x to a var:

struct Foo {
    var x: Int? = nil
}

// So now this work, but x is a `var` :(
let foo = Foo(x: 123)

Is there anyway to get what I want?

1 Like

Why do you want to do what you've stated? As I read the language spec, it kind of goes against what a let (a constant value that can't be changed once initialized) is. If you want a constant value that gets initialized at run-time with a value, then you have to specify the initializer (your second case). In the first case, you initialized x with a nil value, which sets x's value for the remainder of the execution, if I read the language reference correctly. In your first example, you initialized x in the declaration, thus, the auto-generated init has nothing to do, and, since you only have one instance variable, it's a constant, and it's already initialized, the initializer doesn't have any arguments.

1 Like

I just want to achieve this:

Struct Foo {
    let x: Int?

    init(x: Int? = nil) {
        self.x = x
    }
}

without having to manually write the init(), just able to use the compiler generate member wise init().

There's none. That's as concise as you can get.

Why do you want to declare the property with let?

In the vast majority of situations, the right design is to declare all properties var. If you want to prevent mutation, you can use private(set).

private(set) still allows you to mutate the value, just greatly constrains where it can get set, namely, within the object that owns the property. If you want a constant that can be set at runtime, and can't be mutated at all, this is a pretty good approach. But, you have to write the initializer.

I repeat my question: why does @young want this?

I posit, again, that it is almost always not what one actually wants, especially for a value-type.

It's for some SwiftUI widget like this:

struct Foo: View {
    @Binding var value1: Double
    @Binding var value2: Double
    // etc, etc
    let onTouch: (() -> ())?         // these should have default nil value
    let onLongPress: (() -> ())?
    let iconFactory: ((Double) -> Image)?
    // etc, etc
}

I want the optional callback closures to be let and default nil, at the same time, I want to avoid having to write the initializer...it's kind of tedious and anytime I add or subtract something, I must revise the hand written initializer. Seem like a perfect task for the compiler :slight_smile:

(should compiler generated init() support let property with default value?)

1 Like

There is a proposal to fix this problem with @initializable: Explicit Memberwise Initializers