Remove implicit initialization of Optionals?

The compiler currently warns us if we try to use a constant before it is initialized on all paths through the program:

let x: Int
print(x) // Error: "Constant 'x' used before being initialized"

The same thing happens for non-optional variables:

var x: Int
print(x) // Error: "Variable 'x' used before being initialized"

Optional variables and implicitly unwrapped Optionals, however, seem to be silently initialized with .none and can be used before assigning another value to it. The following snippet compiles just fine:

var x: Int?
print(x) // prints "nil"

I think that the default initialization of Optionals is potentially dangerous, as it makes it possible to forget to initialize an Optional with a proper value on some paths:

var x: Int?
if f() {
    x = 5
} else {
    // forgot to initialize x
}
print(x)

Similarly, it makes it possible to forget to initialize stored properties in a struct or class:

struct X {
    init() {
        // forgot to initialize self.x
    }
    var x: Int?
}

The latter becomes especially painful when adding new stored properties to a type that has a lot of initializers — it is super easy to forget initializing the property in one of them.


Personally I don't think there's a reason to implicitly initialize Optionals with .none and treat them any differently than non-optional variables or constants, especially since we can't turn that behavior off. And if that's what we desire, it would be as simple as adding a = nil to the declaration.

What do you guys think about removing the default initialization with .none of Optionals?

2 Likes

For reference this has been brought up before: Pitch: Remove default initialization of optional bindings

1 Like

Thanks for pointing this out, Alejandro.

However, the discussion in the thread you linked was mostly about personal preference — the potential pitfalls I mentioned in my post were not brought up back there and are the primary reason I would like to see this change.

I think for that the ship has sailed because there is too much code out in the wild that relies on that feature especially in context of type properties. Removing it now would end up in a catastrophic source breaking change.

It would indeed be a source-breaking change, but one with a trivial fix: the migrator could simply add = nil to all declarations of optional variables.

In my experience, this behavior isn't actively harmful. I can remember maybe 2 times where I've had bugs because I failed to assign back to the variable, and both of those cases were caught almost immediately by testing.

As for the initializer issue, I would say that if you have so many initializers that forgetting to update one is an issue for you, I'd say you have too many initializers. And again, this type of bug should be caught by your unit testing

The case where I think it is most likely to lead to problems is with IUO. I have long wanted a mechanism similar to IUO, but which requires assignment to a non-nil value during phase 2 of initialization and can never be set to a nil value after initialization (with the option to become immutable after initialization is complete). Something like that would remove most of the danger of implicit initialization to nil.

1 Like