Sometimes we would greatly benefit from being able to access the "parent TYPE" inside some "nested type"/"child type". For example this TCA code:
@Reducer
struct Onboarding {
var body: some ReducerOf<Self> { ... } // `Self` is `Onboarding`
struct View: SwiftUI.View { // `Self` is `Onboarding.View`, cannot access type `Onboarding` here...
let store: StoreOf<Onboarding> // thus have to spell out `Onboarding` here
init(store: StoreOf<Onboarding>) { // and here...
self.store = store
}
}
}
I want to propose being able to access the 'parent type' by use of Parent (which is undefined in a non nested context (would be a compiler error)). Allowing:
@Reducer
struct Onboarding {
var body: some ReducerOf<Self> { ... } // `Self` is `Onboarding`
struct View: SwiftUI.View { // `Self` is `Onboarding.View`, cannot access type `Onboarding` here...
let store: StoreOf<Parent> // 🎉
init(store: StoreOf<Parent>) { // 🎉
self.store = store
}
}
}
This may look like a small thing... but this would allow us to write more powerful Xcode Templates and I believe it will be helpful for macro authors as well.
I think the phrase is "+1 from me". It expresses the intent of referring to the parent itself as opposed to a specific type that just happens to be the parent, which makes the child type's behaviour clearer when refactoring and also more amenable to copy-and-pasting into other parent types.
I think we should NOT use Super since it makes one think about classes and inheritance, which is... a whole different dimension/"axis". That would be inheritance dimension, whereas this is "type nesting" dimension.
I think Super would be good also, for inheritance, but I will leave that for another thread...
Both Parent and Super has tight bounding to the inheritance, while it is about nested types.
As for the issue itself, I don't think that is a huge enough issue to make it part of the language. A simple typealias will do the work:
typealias Store = StoreOf<Onboarding>
I also think that such nesting mostly isn't good (and this mix of a view and reducer particularly) at a large scale, should be used rarely and isn't encouraged by the language tools.
For macros, this would be solved with the following feature instead,
Additionally, this adds a special rule for "types" and adds a new keyword - that's only confusing. How would this also work with types actually called Parent, or any other proposed keyword?
To circumvent that a few project might have a nested type called Parent, one might introduce a new symbol for this kind of language provided type aliases (not typealias): $Self (and let Self simply by a typealias Self = $Self for backwards compatibility) $Parent (which is only defined on nested types, obviously).
This is a good question. I think we should use a syntax that prevent any such collisions, like $wrappedProperty with property wrappers. Something like $EnclosingType / @EnclosingType
For now trying to declare a struct $Parent turns in compiler error: the '$' prefix is reserved for implicitly-synthesized declarations
I think getting this through the .Type metatype would be clear and brief enough: Self.Type.Parent? I'm not really sure what would happen to top level types unless we give it a parent type of Void, if that is theoretically correct.
Void Parent type is an incorrect mental model as all top level types are 1) not nested types 2) are not in Void type namespace, they are in module namespace.
I would prefer compiler error for attempt to reference Enclosing type from top level type.