Type checker not accepting subclass(protocol conformance) as a valid type inside a closure in a protocol with constraint where Self: MyClass


(Henrique Valcanaia) #1

Hey everyone.

I’m having some trouble with the following code, more precisely I’m getting the error "Cannot convert value of type '([Self]?, Error?) -> Void?' to expected argument type ‘([SomeModel]?, Error?) -> Void?’” when trying to call “find2(withBlock: ([SomeModel]?, Error?) -> Void?)” inside my extension.

Here’s a snippet:

protocol SomeModel { }

func find2(withBlock block: ([SomeModel]?, Error?) -> Void?) {
    print(#function)
}

protocol PersistentModel {
    typealias FindBlock = (_ objs: [Self]?, _ error: Error?) -> Void?
    func find(withBlock block: FindBlock)
}

extension PersistentModel where Self: SomeModel {
    func find(withBlock block: FindBlock) {
       find2(withBlock: block)
    }
}

Considering I’m constraining my protocol extension to SomeModel, why do I get the error when trying to call “find(withBlock: ([SomeModel]?, Error?) -> Void?)”? It’s seems to me the type checker is not comparing the parameters' type inside the block and its inheritances/protocol conformances.

Just for testing purposes I created a simple class implementing the protocol and a function with the parameter of the same type, we can see the problem does not occur, being strictly linked to closures.

class MyClass: SomeModel { }

func test(a: SomeModel) { }
test(a: MyClass())

I’m not sure if I’m doing something wrong or if it is just a compiler/language limitation, any thoughts?

Thanks

- Henrique


(Jordan Rose) #2

Hi, Henrique. This is a correct error message. Consider this use case:

struct Impl: PersistentModel {
  func doTheThing()
}

func callback(_ objs: [Impl]?, _ error: Error?) -> Void? {
  return objs.first?.doTheThing()
}
find2(withBlock: callback) // direct call for clarity

Clearly here the ‘callback’ function isn’t compatible with the type ‘find2’ expects—it wants to be able to pass an array of SomeModel to the function, but the function only handles Impl instances specifically. Any other conforming type would be a problem.

Hope that helps,
Jordan

···

On Nov 1, 2016, at 14:48, Henrique Valcanaia via swift-users <swift-users@swift.org> wrote:

Hey everyone.

I’m having some trouble with the following code, more precisely I’m getting the error "Cannot convert value of type '([Self]?, Error?) -> Void?' to expected argument type ‘([SomeModel]?, Error?) -> Void?’” when trying to call “find2(withBlock: ([SomeModel]?, Error?) -> Void?)” inside my extension.

Here’s a snippet:

protocol SomeModel { }

func find2(withBlock block: ([SomeModel]?, Error?) -> Void?) {
    print(#function)
}

protocol PersistentModel {
    typealias FindBlock = (_ objs: [Self]?, _ error: Error?) -> Void?
    func find(withBlock block: FindBlock)
}

extension PersistentModel where Self: SomeModel {
    func find(withBlock block: FindBlock) {
       find2(withBlock: block)
    }
}

Considering I’m constraining my protocol extension to SomeModel, why do I get the error when trying to call “find(withBlock: ([SomeModel]?, Error?) -> Void?)”? It’s seems to me the type checker is not comparing the parameters' type inside the block and its inheritances/protocol conformances.

Just for testing purposes I created a simple class implementing the protocol and a function with the parameter of the same type, we can see the problem does not occur, being strictly linked to closures.

class MyClass: SomeModel { }

func test(a: SomeModel) { }
test(a: MyClass())

I’m not sure if I’m doing something wrong or if it is just a compiler/language limitation, any thoughts?

Thanks

- Henrique

_______________________________________________
swift-users mailing list
swift-users@swift.org
https://lists.swift.org/mailman/listinfo/swift-users