Extensions on nested generics with protocols

If I have an array where the elements conform to MyProtocol and want to create an extension for it, I can do something along the lines of:

extension Array where Element: MyProtocol {
  func myFunc() { ... }
}

Is it possible to write an extension for an array an array of arrays of MyProtocol? I’ve tried a few combinations, but everything results in me having to use <> to define the child generic and that always demands a concrete type.

Ideally, I’d be able to do something like:

extension Array where Element == Array, Element.Element: MyProtocol {
  func myFunc() { ... }
}

The concrete problem I’m trying to solve is that I have a generic lockable type Lockable<T>, which I want to use to hold an array of weak delegates, with helpers:

extension Lockable<Array<WeakHolder<T: AnyObject>>> {
  func add(_ delegate: T)
  func cullAndReturn() -> Array<T>
}

I’ve tried using composition instead with a type WeakDelegateStore<Delegate: AnyObject>, but have run into this issue on consumption: Generic class requires that generic type be a class type

I’m suspecting my only option is to have an array of AnyObject and have cullAndReturn<T>() cast the type on read.

You can usually do something like this by adding generics on the extension function, since you can't do it on the extension itself.

extension Array {
    func doThing<T>() where Element == Array<T> {
        
    }
}
4 Likes

Thanks @Jon_Shier, I completely missed that option!

Would it suffice to constraint the elements to be collections instead of arrays? Because then you could do this:

extension Collection where Element: Collection, Element.Element: MyProtocol { … }
1 Like