4
votes

This isn't critical, and there are workarounds, but it is perplexing.

See the minimal example below. I'm referring to an initialized property, but before calling super.init(). Why does the indicated statement below have a compile error? Is there something special about using the property in the right hand of an expression versus the left hand?

I looked through the Swift language guides and couldn't find anything relevant. Is the swift compiler screwing up here, or is there something about properties, self, and init that I'm missing? Or should all references to "myProperty" be in error before calling super.init?

(Note it doesn't matter if the property is a constant (with 'let') or if the property is another type, like an Int - the same thing happens.)

class MyClass : NSObject {
    var myProperty: Bool

    override init() {
        myProperty = true

        if myProperty { /* this is ok */ }
        if myProperty || true { /* this is ok */ }
        if true || myProperty  { /* this is NOT ok! ('self used before super.init') - WHY? */ }

        super.init()

        if true || myProperty  { /* now this is ok */ }
    }
}
2

2 Answers

4
votes

This is a side-effect of || being declared as

func ||<T : BooleanType>(lhs: T, rhs: @autoclosure () -> Bool) -> Bool

So the compiler treats

true || myProperty

as

true || { self.myProperty }()

The reason is the "short-circuiting" behaviour of the || operator: If the first operand is true, then the second operand must not be evaluated at all.

(Side note: I assume that this is simplified at a later stage in the compiling/optimizing process so that the final code does not actually create and call a closure.)

Accessing self inside the closure causes the error message. You would get the same error for

override init() {
    myProperty = true
    let a = { self }() // ERROR: self used before super.init
    super.init()
    let b = { self }() // OK after super.init
}
0
votes

I think it is intended behavior and part of the two phase initialization.

This is a result of the following rules:

  • All properties must be initialized before super.init is called, that is at the same line as the declaration or in init before super.init
  • An initializer may not call any instance methods, read the values of any instance properties, or refer to self as a value until after the first phase of initialization is complete