1

Say I have these protocols

protocol Actionable {

}

protocol M: class {
    associatedtype Action: Actionable
    var views: [Action] { get set }
}

and two functions

func f(view: Actionable) {

}

func g(views: [Actionable]) {

}

And I extend the protocol M

extension M {
    func add(view: Action) {
        views.append(view)
        f(view)
        g(views)
    }
}

When I call f(view it works. But when I call g(views) it shows error

Cannot convert value of type '[Self.Action]' to expected argument type '[Actionable]'

Here g accepts an array instead of a single object like f. Why does array matter in this case? How to work around this?

As a side note, this seems to be the kind of error for generic struct, too

protocol Actionable {

}

struct M<T: Actionable> {
  var views: [T]
}

func g(views: [Actionable]) {

}

extension M {
  func add() {
    g(views)
  }
}
onmyway133
  • 45,645
  • 31
  • 257
  • 263

1 Answers1

1

This is an extension of the fact that arrays in Swift have limitations with the types they can implicitly converted to – which is a consequence of the invariance of generics in Swift, which I discuss further in this post.

One possible solution is to use map in order to convert each element individually from Action to Actionable (the elements can be freely up-cast, but the array itself cannot):

extension M {
    func add(view: Action) {
        views.append(view)
        f(view)
        g(views.map{$0})
    }
}

However in your specific situation, I would simply recommend making your f and g functions generic in order to maintain the concrete type that you supply to them (unless you specifically want them to be type-erased):

func f<T:Actionable>(view: T) {
    ...
}

func g<T:Actionable>(views: [T]) {
    ...
}

extension M {
    func add(view: Action) {
        views.append(view)
        f(view)
        g(views)
    }
}

Now the generic type of Action will be maintained when you call them, providing you with better type-safety if you want to pass the argument around.

Community
  • 1
  • 1
Hamish
  • 78,605
  • 19
  • 187
  • 280