Protocol conformance error

Hi,

Cross posting from swift-users in case this behaviour isn't part of
the language and might be interesting to you folks.

Here is some sample code that gives a protocol conformance error in a
playground:

protocol A {}
protocol B: A {}

protocol C {
    func test(x: A)
}

class M: C {
    func test(x: B) {}
}

Is there a reason why the compiler doesn't infer that ((B) -> ())
matches ((A) -> ()) because of inheritance?

···

--
Warm regards
Roshan

If we have:

class N: A {}

you can pass an N into C’s test(x:), since N is an A, but not M’s test(x:), since N is not a B. Thus, it’s not a valid conformance.

Saagar Jha

···

On Jan 17, 2018, at 00:04, Roshan via swift-evolution <swift-evolution@swift.org> wrote:

Hi,

Cross posting from swift-users in case this behaviour isn't part of
the language and might be interesting to you folks.

Here is some sample code that gives a protocol conformance error in a
playground:

protocol A {}
protocol B: A {}

protocol C {
   func test(x: A)
}

class M: C {
   func test(x: B) {}
}

Is there a reason why the compiler doesn't infer that ((B) -> ())
matches ((A) -> ()) because of inheritance?

--
Warm regards
Roshan
_______________________________________________
swift-evolution mailing list
swift-evolution@swift.org
https://lists.swift.org/mailman/listinfo/swift-evolution

Note that it would be sound for the language to allow the opposite, which is called “contravariance” (the more specific type takes a more general input):

    protocol A {}
    protocol B: A {}

    protocol C {
       func test(x: B) // was A
    }

    class M: C {
       func test(x: A) {} // was B
    }

It could also allow covariant return types (the more specific type returns a more specific output):

    protocol C {
       func test() -> A
    }

    class M: C {
       func test() -> B {
          fatalError("just a stub")
       }
    }

Some languages support this, and Swift certainly could — though I don’t know that it’s a frequently request feature.

It would also be interesting if associated type constraints allowed this, which I don’t think they currently do:

    protocol C {
       associatedtype TestInput where B: TestInput // error here

       func test(x: TestInput)
    }

Curiously, the following does not work, although it seems like it should:

    protocol A {}
    protocol B: A {}

    protocol C {
       associatedtype TestOutput: A

       func test() -> TestOutput
    }

    class M: C {
       func test() -> B {
          fatalError("just a stub")
       }
    }

It gives the error “inferred type 'B' (by matching requirement 'test()') is invalid: does not conform to ‘A’” even though B does conform to A. Huh.

Cheers, P

···

On Jan 17, 2018, at 2:43 AM, Saagar Jha via swift-evolution <swift-evolution@swift.org> wrote:

If we have:

class N: A {}

you can pass an N into C’s test(x:), since N is an A, but not M’s test(x:), since N is not a B. Thus, it’s not a valid conformance.

Saagar Jha

On Jan 17, 2018, at 00:04, Roshan via swift-evolution <swift-evolution@swift.org <mailto:swift-evolution@swift.org>> wrote:

Hi,

Cross posting from swift-users in case this behaviour isn't part of
the language and might be interesting to you folks.

Here is some sample code that gives a protocol conformance error in a
playground:

protocol A {}
protocol B: A {}

protocol C {
   func test(x: A)
}

class M: C {
   func test(x: B) {}
}

Is there a reason why the compiler doesn't infer that ((B) -> ())
matches ((A) -> ()) because of inheritance?

--
Warm regards
Roshan
_______________________________________________
swift-evolution mailing list
swift-evolution@swift.org <mailto:swift-evolution@swift.org>
https://lists.swift.org/mailman/listinfo/swift-evolution

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

Interestingly, it seems like Swift allows for contravariance for subclassing, in that this is valid code:

protocol A {}
protocol B: A {}

class C { // Notice this is a class, not a protocol
   func test(x: B) {}
}

class M: C {
   func test(x: A) {}
}

Is it an oversight that this doesn’t apply to protocols?

Saagar Jha

···

On Jan 17, 2018, at 11:38, Paul Cantrell <cantrell@pobox.com> wrote:

Note that it would be sound for the language to allow the opposite, which is called “contravariance” (the more specific type takes a more general input):

    protocol A {}
    protocol B: A {}

    protocol C {
       func test(x: B) // was A
    }

    class M: C {
       func test(x: A) {} // was B
    }

It could also allow covariant return types (the more specific type returns a more specific output):

    protocol C {
       func test() -> A
    }

    class M: C {
       func test() -> B {
          fatalError("just a stub")
       }
    }

Some languages support this, and Swift certainly could — though I don’t know that it’s a frequently request feature.

It would also be interesting if associated type constraints allowed this, which I don’t think they currently do:

    protocol C {
       associatedtype TestInput where B: TestInput // error here

       func test(x: TestInput)
    }

Curiously, the following does not work, although it seems like it should:

    protocol A {}
    protocol B: A {}

    protocol C {
       associatedtype TestOutput: A

       func test() -> TestOutput
    }

    class M: C {
       func test() -> B {
          fatalError("just a stub")
       }
    }

It gives the error “inferred type 'B' (by matching requirement 'test()') is invalid: does not conform to ‘A’” even though B does conform to A. Huh.

Cheers, P

On Jan 17, 2018, at 2:43 AM, Saagar Jha via swift-evolution <swift-evolution@swift.org <mailto:swift-evolution@swift.org>> wrote:

If we have:

class N: A {}

you can pass an N into C’s test(x:), since N is an A, but not M’s test(x:), since N is not a B. Thus, it’s not a valid conformance.

Saagar Jha

On Jan 17, 2018, at 00:04, Roshan via swift-evolution <swift-evolution@swift.org <mailto:swift-evolution@swift.org>> wrote:

Hi,

Cross posting from swift-users in case this behaviour isn't part of
the language and might be interesting to you folks.

Here is some sample code that gives a protocol conformance error in a
playground:

protocol A {}
protocol B: A {}

protocol C {
   func test(x: A)
}

class M: C {
   func test(x: B) {}
}

Is there a reason why the compiler doesn't infer that ((B) -> ())
matches ((A) -> ()) because of inheritance?

--
Warm regards
Roshan
_______________________________________________
swift-evolution mailing list
swift-evolution@swift.org <mailto:swift-evolution@swift.org>
https://lists.swift.org/mailman/listinfo/swift-evolution

_______________________________________________
swift-evolution mailing list
swift-evolution@swift.org <mailto:swift-evolution@swift.org>
https://lists.swift.org/mailman/listinfo/swift-evolution

class M: C {
   func test(x: A) {}
}
there's no "override" keyword, so I think you're overloading.

C. Keith Ray
https://leanpub.com/wepntk <- buy my book?
http://agilesolutionspace.blogspot.com/
twitter: @ckeithray
http://www.thirdfoundationsw.com/keith_ray_resume_2014_long.pdf

···

On Jan 17, 2018, at 11:53 AM, Saagar Jha via swift-evolution <swift-evolution@swift.org> wrote:

Interestingly, it seems like Swift allows for contravariance for subclassing, in that this is valid code:

protocol A {}
protocol B: A {}

class C { // Notice this is a class, not a protocol
   func test(x: B) {}
}

class M: C {
   func test(x: A) {}
}

Is it an oversight that this doesn’t apply to protocols?

Saagar Jha

On Jan 17, 2018, at 11:38, Paul Cantrell <cantrell@pobox.com> wrote:

Note that it would be sound for the language to allow the opposite, which is called “contravariance” (the more specific type takes a more general input):

    protocol A {}
    protocol B: A {}

    protocol C {
       func test(x: B) // was A
    }

    class M: C {
       func test(x: A) {} // was B
    }

It could also allow covariant return types (the more specific type returns a more specific output):

    protocol C {
       func test() -> A
    }

    class M: C {
       func test() -> B {
          fatalError("just a stub")
       }
    }

Some languages support this, and Swift certainly could — though I don’t know that it’s a frequently request feature.

It would also be interesting if associated type constraints allowed this, which I don’t think they currently do:

    protocol C {
       associatedtype TestInput where B: TestInput // error here

       func test(x: TestInput)
    }

Curiously, the following does not work, although it seems like it should:

    protocol A {}
    protocol B: A {}

    protocol C {
       associatedtype TestOutput: A

       func test() -> TestOutput
    }

    class M: C {
       func test() -> B {
          fatalError("just a stub")
       }
    }

It gives the error “inferred type 'B' (by matching requirement 'test()') is invalid: does not conform to ‘A’” even though B does conform to A. Huh.

Cheers, P

On Jan 17, 2018, at 2:43 AM, Saagar Jha via swift-evolution <swift-evolution@swift.org> wrote:

If we have:

class N: A {}

you can pass an N into C’s test(x:), since N is an A, but not M’s test(x:), since N is not a B. Thus, it’s not a valid conformance.

Saagar Jha

On Jan 17, 2018, at 00:04, Roshan via swift-evolution <swift-evolution@swift.org> wrote:

Hi,

Cross posting from swift-users in case this behaviour isn't part of
the language and might be interesting to you folks.

Here is some sample code that gives a protocol conformance error in a
playground:

protocol A {}
protocol B: A {}

protocol C {
   func test(x: A)
}

class M: C {
   func test(x: B) {}
}

Is there a reason why the compiler doesn't infer that ((B) -> ())
matches ((A) -> ()) because of inheritance?

--
Warm regards
Roshan
_______________________________________________
swift-evolution mailing list
swift-evolution@swift.org
https://lists.swift.org/mailman/listinfo/swift-evolution

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

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

I remember discussions on this list of curious situations in which a protocol doesn’t even conform to itself. This may be related.

I’ll let others who better understand the type system and its limitations weigh in.

P

···

On Jan 17, 2018, at 1:53 PM, Saagar Jha <saagar@saagarjha.com> wrote:

Interestingly, it seems like Swift allows for contravariance for subclassing, in that this is valid code:

protocol A {}
protocol B: A {}

class C { // Notice this is a class, not a protocol
   func test(x: B) {}
}

class M: C {
   func test(x: A) {}
}

Is it an oversight that this doesn’t apply to protocols?

Saagar Jha

On Jan 17, 2018, at 11:38, Paul Cantrell <cantrell@pobox.com <mailto:cantrell@pobox.com>> wrote:

Note that it would be sound for the language to allow the opposite, which is called “contravariance” (the more specific type takes a more general input):

    protocol A {}
    protocol B: A {}

    protocol C {
       func test(x: B) // was A
    }

    class M: C {
       func test(x: A) {} // was B
    }

It could also allow covariant return types (the more specific type returns a more specific output):

    protocol C {
       func test() -> A
    }

    class M: C {
       func test() -> B {
          fatalError("just a stub")
       }
    }

Some languages support this, and Swift certainly could — though I don’t know that it’s a frequently request feature.

It would also be interesting if associated type constraints allowed this, which I don’t think they currently do:

    protocol C {
       associatedtype TestInput where B: TestInput // error here

       func test(x: TestInput)
    }

Curiously, the following does not work, although it seems like it should:

    protocol A {}
    protocol B: A {}

    protocol C {
       associatedtype TestOutput: A

       func test() -> TestOutput
    }

    class M: C {
       func test() -> B {
          fatalError("just a stub")
       }
    }

It gives the error “inferred type 'B' (by matching requirement 'test()') is invalid: does not conform to ‘A’” even though B does conform to A. Huh.

Cheers, P

On Jan 17, 2018, at 2:43 AM, Saagar Jha via swift-evolution <swift-evolution@swift.org <mailto:swift-evolution@swift.org>> wrote:

If we have:

class N: A {}

you can pass an N into C’s test(x:), since N is an A, but not M’s test(x:), since N is not a B. Thus, it’s not a valid conformance.

Saagar Jha

On Jan 17, 2018, at 00:04, Roshan via swift-evolution <swift-evolution@swift.org <mailto:swift-evolution@swift.org>> wrote:

Hi,

Cross posting from swift-users in case this behaviour isn't part of
the language and might be interesting to you folks.

Here is some sample code that gives a protocol conformance error in a
playground:

protocol A {}
protocol B: A {}

protocol C {
   func test(x: A)
}

class M: C {
   func test(x: B) {}
}

Is there a reason why the compiler doesn't infer that ((B) -> ())
matches ((A) -> ()) because of inheritance?

--
Warm regards
Roshan
_______________________________________________
swift-evolution mailing list
swift-evolution@swift.org <mailto:swift-evolution@swift.org>
https://lists.swift.org/mailman/listinfo/swift-evolution

_______________________________________________
swift-evolution mailing list
swift-evolution@swift.org <mailto:swift-evolution@swift.org>
https://lists.swift.org/mailman/listinfo/swift-evolution