2

I'm trying to cast a generic type to its super class.

class Foo : NSObject {
}
class Test<T> {
    let value: T
    init(_ value: T) {
        self.value = value
    }
}

let c = Test(Foo())
let v = c as Test<AnyObject>

But on the line

let v = c as Test<AnyObject>

I get 'Foo' is not identical to 'AnyObject'

While I can do that with built-in Arrays

let array1 = [Foo(), Foo()]
let array2 = array1 as [AnyObject]
mohamede1945
  • 7,092
  • 6
  • 47
  • 61

1 Answers1

1

Arrays are special-cased in Swift to be able to have this behaviour. You won't be able to replicate it with your own classes, unfortunately.

To get similar behaviour, you could give your type another init method:

class Test<T> {
    let value: T
    init(_ value: T) {
        self.value = value
    }

    init<U>(other: Test<U>) {
        // in Swift 1.2 you will need as! here
        self.value = other.value as T
    }
}

let c = Test(Foo())
let v = Test<AnyObject>(other: c)  // this will work ok

Note though that this is unsafe (i.e. will assert at runtime) in cases where you want to convert to an incompatible type (and the alternative, a failable initializer, will also have complications)

Airspeed Velocity
  • 40,491
  • 8
  • 113
  • 118
  • 1
    Edited my answer to match, but it still won't work I'm afraid. Generic types just aren't covariant in Swift. See [this article](http://nomothetis.svbtle.com/type-variance-in-swift). You never know, this might change in future versions (but don't count on it, this kind of variance brings a world of pain to languages that support it) – Airspeed Velocity Apr 07 '15 at 14:58
  • You have to expound on "this kind of variance brings a world of pain to languages that support it." I demand a blog post. – Rob Napier Apr 07 '15 at 17:13
  • @Rob for example, the 6-figure reputation gods of C# [weigh in](http://stackoverflow.com/questions/4317459/why-is-array-co-variance-considered-so-horrible). The question gives the classic C# covariant array prob. Of course, Swift arrays don't have this problem, being value types. But shows how extending covariance to reference types could lead to tragedy if not done super carefully. – Airspeed Velocity Apr 07 '15 at 19:36
  • Swift was wise to make implicit elevation to Any* illegal of course, so that's not usually an issue (I've definitely had the fun he's describing in Scala; but [T] is covariant, too…) But I think the "on value types" point is very important and does make many problems go away. And Swift has some pretty clear dividing lines between value and reference types that help. (But I'm not disagreeing that the problem is subtle and tricky, and better too strict and too lenient.) – Rob Napier Apr 07 '15 at 20:15