Generic method constraints on sub-properties

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.

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 { ... }

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.

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).

Terms of Service

Privacy Policy

Cookie Policy