Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Swift generic type cast

I have a generic class where I have an array of generic types. No I want to do some operations based on the class in the array. I have 2 classes: Person and House (no Inheritance). But this code doesn't work:

let allValues = [T]()
if allValues[0] is Person { 
     let values = (allValues as [Person])
}

But this doesn't work as T is not identical to 'Person'. What do I have to do? Thanks for any help.

like image 492
borchero Avatar asked Dec 21 '14 16:12

borchero


People also ask

What is generic type in Swift?

Generic code enables you to write flexible, reusable functions and types that can work with any type, subject to requirements that you define. You can write code that avoids duplication and expresses its intent in a clear, abstracted manner.

What is difference between generic and any swift?

Generics and Any are often used for similar purposes, yet they behave very differently. In languages without generics, you typically use a combination of Any and runtime programming, whereas generics are statically checked at compile time.


2 Answers

You can’t do this (or at least, not without jumping through some pretty tortuous and inadvisable hoops). You are thinking of T more like the Any type, which is a type that can hold any other type and that you can turn back into the real type with as (or probably preferably as?) at runtime.

But generics don’t work like this. Within your code, the generic T will be replaced with a real type at compile time, and that type might not be a Person. What would the code above do if that were the case?

What is the underlying functionality you’re actually trying to achieve? People and houses are very different so do you really need to write a function that operates generically on both of them?

like image 124
Airspeed Velocity Avatar answered Sep 28 '22 10:09

Airspeed Velocity


I agree with Oliver Borchert and Airspeed Velocity: this kind of problem should be addressed using a protocol.

However you can perform the cast you asked about using this syntax:

let values = allValues as Any as [Person]

Now I see 2 problems:

  1. Your IF will crash because your array allValues contains 0 elements and you are accessing the first one (that does not exist).
  2. allValues could have a Person at the first element and something else at the second position. This makes dangerous a cast after having evaluated only the first element.

    Example

    class LifeForm {}

    class Person : LifeForm {}

    With T equals to LifeForm.

I think the following version is safer because you are directly evaluating the type T.

class Things<T>{
    func doSomething() {
        let allValues = [T]()
        // populate allValues....
        if T.self is Person.Type {
            println("List of Person")
            let values = allValues as Any as [Person]
        }
    }
}

Important: I provided this code just to show the syntax. I don't like this abborach (again, a Protocol would be better) because the class Things contains logic specific to Person. Ideally Things should know nothing about Person because Things is a generic class.

like image 27
Luca Angeletti Avatar answered Sep 28 '22 11:09

Luca Angeletti