Is this correct? Child type of Struct can access parent Struct's Type property as if it were an instance property

Hello,

I defined a struct with a type property. I also defined a child type of that type and accidentally referred to the parent's type property as if it were an instance property of the child type. Unexpectedly this did not produce an error.

Is this correct behaviour?

I see that this post from @Slava_Pestov may explain it, but I have to admit that I don't quite understand it fully.

import Foundation


struct Struct1 {
	static let staticLetProperty = "Hello, I am a static let property on the Struct1 Type"
	let instanceProperty = "I am an instance property of an instance of Struct1"
	
	class ChildClass {
		func doThing() {
			print(staticLetProperty)
		}
	}
}


let test1 = Struct1()

//	This works as expected
print(test1.instanceProperty)

//  This doesn't work, as expected
//	Error: Static member 'staticLetProperty' cannot be used on instance of type 'Struct1'
print(test1.staticLetProperty)

let test2 = Struct1.ChildClass()

//	Prints "Hello, I am a static let property on the Struct1 Type" - Is this correct?
test2.doThing()


1 Like

It's applicable to all enclosing types, not just the direct one:

Here's an example of using self in a type context. You currently have the idea that this is "as if it were an instance property", but that's not the case. self just means something different here, than it does in an instance member. And nobody ever uses it explicitly.

extension Struct1 {
  static var staticComputedProperty: String { self.staticLetProperty }
}

Struct1 static members will trickle down to ChildClass, but only in the definition. If you use extensions, you'll need to qualify where the static member is coming from. I consider the inconsistency a bug but there may be reasons it has to work that way.

extension Struct1.ChildClass {
  func doThing() {
    print(Struct1.staticLetProperty)
  }
}
1 Like

Thanks very much @anon9791410

1 Like

I don’t think there’s any real reason it has to work that way, but it’s explainable as follows: unqualified (bare identifier) lookup visits each outer lexical context in turn and performs a qualified (member) lookup into each context. It doesn’t walk the “logical” parent contexts of an extension of a nested type, so it won’t do a qualified lookup into Struct1 at all. But it could (C++ basically implements the rule you’re thinking of, except instead of extensions they have whatever their term is for member declarations outside of a class)

4 Likes