Casting for a universal option in Swift

I fiddled with generics in Swift and clicked on something that I can’t understand: if I pass the value to the type of the general parameter, then the cast does not work. 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 anyone explain this behavior? Shouldn't both be equivalent?

Update

The above example is simplified to max. The following example illustrates the need for casting 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") } 

Second 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 is 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 to use init?(param: Any) before, but this gives the same problem as in the previous if , which is discussed elsewhere .

So it all boils down to: Has anyone really been far from ever casting something to a universal optional type? Anyway? I am happy to accept any working example.

+6
source share
3 answers

This works as expected now - on playgrounds, as well as in projects.

0
source

This is 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 enters the dictionary before [String:AnyObject] , you are in the same boat.

+2
source

As far as I can see, the purpose of your updated code is to find out if the passed parameter (dict value) is of type T. So, you are using as incorrectly? to check the type. What you really want is the "is" operator.

 class SomeClass<T> { init?(v: [String: AnyObject]) { if v["k"] is T { print("called if AnyObject is of type T") } else { print("called if AnyObject is not of type T") return nil } } } if let _ = SomeClass<Int>(v: ["k": 4]) { print("called") } if let _ = SomeClass<Int?>(v: ["k": 4]) { print("not called") } 
0
source

All Articles