[swift-users] question about covariant subtyping

Michael Roitzsch reactorcontrol at icloud.com
Wed Feb 22 10:50:46 CST 2017


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 at 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 at 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



More information about the swift-users mailing list