question about covariant subtyping


(Michael Roitzsch) #1

Hi all,

I am fairly new to Swift, so this may very well be a simple misunderstanding on my part.

I was exploring the subtyping rules of Swift, especially regarding covariance. I came across two examples where the outcome puzzles me and I would appreciate if someone could explain this to me.

First I tried the covariance for the standard container types. Here is an excerpt from a REPL session:

Michael@carpo:~ > swift
Welcome to Apple Swift version 3.0.2 (swiftlang-800.0.63 clang-800.0.42.1). Type :help for assistance.
  1> open class Super {}; class Sub: Super {}
  2> print([Sub()] is [Sub])
true
  3> print([Sub()] is [Super])
true
  4> print(Array<Sub>(arrayLiteral: Sub()) is [Sub])
true
  5> print(Array<Sub>(arrayLiteral: Sub()) is [Super])
error: repl.swift:5:39: error: 'Super' is not a subtype of 'Sub'
print(Array<Sub>(arrayLiteral: Sub()) is [Super])
      ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~^~~~~~~~~~

Why does it matter for subtyping against [Super] whether I express an array as [Sub] or Array<Sub>(arrayLiteral: Sub())?

Then I tried combining array covariance with function argument type contravariance:

Michael@carpo:~ > swift
Welcome to Apple Swift version 3.0.2 (swiftlang-800.0.63 clang-800.0.42.1). Type :help for assistance.
  1> open class Super {}; class Sub: Super {}
  2> func f(_: [Super]) {}
  3> let test: ([Sub]) -> Void = f
error: repl.swift:3:29: error: cannot convert value of type '([Super]) -> ()' to specified type '([Sub]) -> Void'
let test: ([Sub]) -> Void = f
                            ^

Why is this assignment not possible? It works fine (as expected) when using plain Super and Sub instead of arrays.

Michael


(Joe Groff) #2

Those are both bugs. There's no fundamental reason these should be errors.

-Joe

···

On Feb 22, 2017, at 8:50 AM, Michael Roitzsch via swift-users <swift-users@swift.org> wrote:

Hi all,

I am fairly new to Swift, so this may very well be a simple misunderstanding on my part.

I was exploring the subtyping rules of Swift, especially regarding covariance. I came across two examples where the outcome puzzles me and I would appreciate if someone could explain this to me.

First I tried the covariance for the standard container types. Here is an excerpt from a REPL session:

Michael@carpo:~ > swift
Welcome to Apple Swift version 3.0.2 (swiftlang-800.0.63 clang-800.0.42.1). Type :help for assistance.
1> open class Super {}; class Sub: Super {}
2> print([Sub()] is [Sub])
true
3> print([Sub()] is [Super])
true
4> print(Array<Sub>(arrayLiteral: Sub()) is [Sub])
true
5> print(Array<Sub>(arrayLiteral: Sub()) is [Super])
error: repl.swift:5:39: error: 'Super' is not a subtype of 'Sub'
print(Array<Sub>(arrayLiteral: Sub()) is [Super])
     ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~^~~~~~~~~~

Why does it matter for subtyping against [Super] whether I express an array as [Sub] or Array<Sub>(arrayLiteral: Sub())?

Then I tried combining array covariance with function argument type contravariance:

Michael@carpo:~ > swift
Welcome to Apple Swift version 3.0.2 (swiftlang-800.0.63 clang-800.0.42.1). Type :help for assistance.
1> open class Super {}; class Sub: Super {}
2> func f(_: [Super]) {}
3> let test: ([Sub]) -> Void = f
error: repl.swift:3:29: error: cannot convert value of type '([Super]) -> ()' to specified type '([Sub]) -> Void'
let test: ([Sub]) -> Void = f
                           ^

Why is this assignment not possible? It works fine (as expected) when using plain Super and Sub instead of arrays.


(Slava Pestov) #3

It looks intentional.

Function conversions can be performed on argument and return types that are related via ‘Subtype’ constraints in the constraint solver, however array conversions are only possible via the ‘Conversion’ relation.

Changing this would require some additional work in SILGen to support such function conversions.

Slava

···

On Feb 22, 2017, at 3:06 PM, Joe Groff via swift-users <swift-users@swift.org> wrote:

On Feb 22, 2017, at 8:50 AM, Michael Roitzsch via swift-users <swift-users@swift.org> wrote:

Hi all,

I am fairly new to Swift, so this may very well be a simple misunderstanding on my part.

I was exploring the subtyping rules of Swift, especially regarding covariance. I came across two examples where the outcome puzzles me and I would appreciate if someone could explain this to me.

First I tried the covariance for the standard container types. Here is an excerpt from a REPL session:

Michael@carpo:~ > swift
Welcome to Apple Swift version 3.0.2 (swiftlang-800.0.63 clang-800.0.42.1). Type :help for assistance.
1> open class Super {}; class Sub: Super {}
2> print([Sub()] is [Sub])
true
3> print([Sub()] is [Super])
true
4> print(Array<Sub>(arrayLiteral: Sub()) is [Sub])
true
5> print(Array<Sub>(arrayLiteral: Sub()) is [Super])
error: repl.swift:5:39: error: 'Super' is not a subtype of 'Sub'
print(Array<Sub>(arrayLiteral: Sub()) is [Super])
    ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~^~~~~~~~~~

Why does it matter for subtyping against [Super] whether I express an array as [Sub] or Array<Sub>(arrayLiteral: Sub())?

Then I tried combining array covariance with function argument type contravariance:

Michael@carpo:~ > swift
Welcome to Apple Swift version 3.0.2 (swiftlang-800.0.63 clang-800.0.42.1). Type :help for assistance.
1> open class Super {}; class Sub: Super {}
2> func f(_: [Super]) {}
3> let test: ([Sub]) -> Void = f
error: repl.swift:3:29: error: cannot convert value of type '([Super]) -> ()' to specified type '([Sub]) -> Void'
let test: ([Sub]) -> Void = f
                          ^

Why is this assignment not possible? It works fine (as expected) when using plain Super and Sub instead of arrays.

Those are both bugs. There's no fundamental reason these should be errors.

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


(Michael Roitzsch) #4

So I understand that the first issue is a bug and the second may be a bug or may be intentional. Would you advise that I file them both as bugs then?

Michael


(Joe Groff) #5

They're both bugs, ultimately. Slava was just pointing out that the second may be due to implementation limitations rather than oversight; either way, we should ultimately remove the limitation.

-Joe

···

On Feb 23, 2017, at 4:45 AM, Michael Roitzsch <reactorcontrol@icloud.com> wrote:

So I understand that the first issue is a bug and the second may be a bug or may be intentional. Would you advise that I file them both as bugs then?


(Michael Roitzsch) #6

They're both bugs, ultimately. Slava was just pointing out that the second may be due to implementation limitations rather than oversight; either way, we should ultimately remove the limitation.

Thanks Joe. So created myself an account with the Swift JIRA. A variant of the first bug has already been reported as SR-3672. I filed the second one as SR-4075.

Michael