Search code examples
swiftstatic-variables

Why can I define a static constant that depends on another static constant in the same type, but not for properties?


I am familiar with getting an error when trying to access self before all the properties are initialized. One thing I never understood is why I can initialize static constants with dependencies on other static properties in the same type without any error.

What is the reason about this behavior? Why does defining static constants don't give me a compile time error and property constants does?

Some code:

struct MyStruct {
    static let myStatic = 1
    // No error on this line...
    static let myStaticPlusOne = myStatic + 1

    let myInstance = 1
    // ... But a compile time error on this one! What makes the difference?
    let myInstancePlusOne = myInstance + 1
}

There has to be a time when this struct gets loaded into the memory or whatever at sometime, loading the static variables. I see this time exactly the same as the time a new instance is created of a type. I can not clearly see the difference between those two. Both have a time where one property is initialized and the other isn't. Than why can I still have access to my static variable from another static variable?


Solution

  • Type and instance.

    • The type MyStruct always exists. static properties belong to the type. So they just sit there and can do anything they like or be related in any way. Okay, yes, it has to come into existence when the program starts, but under the hood the static property initializers are all lazy so it's okay for one to depend on another (not in a circular way of course).

    • An instance of MyStruct is a thing that has to be created, each time you say MyStruct(...). When you say that, the instance properties must be initialized. An instance (not static) property belongs to the instance. So its initializer's value cannot refer to self because self is exactly what we are in the middle of creating, i.e. the instance. This line:

      let myInstancePlusOne = myInstance + 1
      

      ...really means

      let myInstancePlusOne = self.myInstance + 1
      

      ...but that is exactly what you are not allowed to say; at the time you are initializing this property there is no self yet, it is what you are initializing. And you can work around this by declaring that property lazy (with other adjustments in the syntax).