Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Casting to generic optional in Swift

I'm fiddling around with generics in Swift and hit something I can't figure out: If I cast a value into the type of a generic parameter, the cast is not performed. If I try the same with static types, it works.

class SomeClass<T> {
    init?() {
        if let _ = 4 as? T {
            println("should work")
        } else {
            return nil
        }
    }
}

if let _ = SomeClass<Int?>() {
    println("not called")
}

if let _ = 4 as? Int? {
    println("works")
}

Can anybody explain this behavior? Shouldn't be both cases equivalent?

Update

The above example is simplified to the max. The following example illustrates the need for a cast a little better

class SomeClass<T> {
    init?(v: [String: AnyObject]) {
        if let _ = v["k"] as? T? {
            print("should work")
        } else {
            print("does not")
            return nil
        }
    }
}

if let _ = SomeClass<Int?>(v: ["k": 4]) {
    print("not called")
}

if let _ = SomeClass<Int>(v: ["k": 4]) {
    print("called")
}

2nd Update

After @matt made me learn about AnyObject and Any and @Darko pointed out in his comments how dictionaries make my example too complicated, here's my next refinement

class SomeClass<T> {
    private var value: T!

    init?<U>(param: U) {
        if let casted = param as? T {
            value = casted
        } else {
            return nil
        }
    }
}


if let _ = SomeClass<Int?>(param: Int(4)) {
    println("not called")
}

if let _ = SomeClass<Int>(param: Int(4)) {
    println("called")
}

if let _ = Int(4) as? Int? {
    println("works")
}

if let _ = (Int(4) as Any) as? Int? {
    println("Cannot downcast from Any to a more optional type 'Int?'")
}

I tried using init?(param: Any) before, but that yields the same problem illustrated in the last if which is discussed elsewhere.

So all it comes down to: Has anyone really been far as to ever cast anything to a generic optional type? In any case? I'm happy to accept any working example.

like image 466
Sebastian Avatar asked Aug 18 '15 18:08

Sebastian


1 Answers

This is really not about generics at all; it's about AnyObject (and how casting works). Consider:

    let d = ["k":1]
    let ok = d["k"] is Int?
    print (ok) // true

    // but:

    let d2 = d as [String:AnyObject]
    let ok2 = d2["k"] is Int?
    print (ok2) // false, though "is Int" succeeds

Since your initializer casts the dictionary up to [String:AnyObject] you are in this same boat.

like image 82
matt Avatar answered Sep 21 '22 12:09

matt