ebg
1
Is it possible in Swift to create a generic constraint on sub-properties of the argument? For example, in this contrived example I have:
protocol LifecycleEmitting: UIView { ... }
protocol Viewing {
var view: UIView { get }
}
protocol Emedding {
var view: Viewing { get }
}
And I want to create an embed function that only operates on views that conforms to LifecycleEmitting. Today, I have to use runtime checks and crash or return:
func embed(embedder: Emedding) {
guard let lifecycleView = embedder.viewing as? LifecycleEmitting else {
fatalError()
}
...
}
I should instead be able to enforce at compile time that my sub-property conforms to the type, using a constraint that's something like:
func embed<T: Emedding where T.view: LifecycleEmitting>(embedder: T) {
let lifecycleView = embedder.viewing
...
}
Is this a limitation of Swift generics? Is it on the generics roadmap? Seems gamechangingly useful.
xwu
(Xiaodi Wu)
2
Your protocol has a member view of concrete type Viewing, which is an existential type. This is why you can't spell what you want to do:
func embed<T: Emedding where T.view: LifecycleEmitting>(embedder: T) {
^~~~ You need to name a type, but this isn't one
Of course, there's no sense in trying to write where T.Viewing: LifecycleEmitting, because Viewing is a concrete type that doesn't conform to LifecycleEmitting. What you want instead is an associated type:
protocol Embedding {
associatedtype View
var view: View { get }
}
Then you can write:
func embed<T: Embedding>(embedder: T) where T.View: LifecycleEmitting { ... }
ebg
3
I'd have to change that to
associatedtype View: Viewing
to preserve the requirements of Embedding, right? Hmm, unfortunately just updating Emedding to use an associated type with a Viewing constraint isn't passing the compiler in other places that conformed to it, investigating.
xwu
(Xiaodi Wu)
4
I assumed there were some errors in the original question in simplifying a larger design for the purpose of asking the question. I don't think you mean to have an associated type constrained to both LifecycleEmitting (to which some UIView classes conform) and Viewing (which contains a UIView instance).