Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Generic class as Parameter

Tags:

generics

swift

I was trying to use generics to get away with a lot of casting. I will provide a simple example:

import UIKit

class List<T> {
    let items: [T]

    init(items: [T]) {
        self.items = items
    }
}

class ListsViewController: UIViewController {
     var lists: [List<AnyObject>] = []
}

let viewController = ListsViewController()
let lists = [List(items: ["Fruits"])]
viewController.lists = lists
                       ^ error "String" is not identical to "AnyObject"

I've read that i could do

class ListsViewController<T>: UIViewController

but than i would have the problem further down the chain where i have to save ListsViewController instances...so that doesn't help.

What i don't get here why does the example work with the default Swift Arrays:

import UIKit

class ListsViewController: UIViewController {
     var lists: [AnyObject] = []
}

let viewController = ListsViewController()
let lists = ["Fruits", "Meat"]
viewController.lists = lists

No error although lists is of type [String] not [AnyObject]. Can i get the same behaviour for my generic class as well?

Thanks so much for your help in advance!

like image 855
warly Avatar asked Dec 02 '25 08:12

warly


1 Answers

Update 8/22/2016: As @DeFrenZ pointed out in the comments, my example relies on collections being reference types. However, in Swift, collections are value types. So if you could compile my example, I don't think there would be any issues. The variables lists and lists2 are separate collections. Mutating one will not affect the other.

Original post continues below:

In addition to my comments above and the link I shared http://nomothetis.svbtle.com/type-variance-in-swift (by Alexandros Salazar) it's worth pointing out why covariance of collections (with no constraints) is generally not type safe.

Here's an example:

var lists: [List<AnyObject>] = []
var lists2: [List<String>] = List(items: ["Fruits"])
lists = lists2            // lists is now an alias for lists2 and is a reference to a list of strings
lists.append(MyObject())  // Now I just put a MyObject into a list of strings
var str:String = lists2[1] // assuming the previous lines compiled and ran ok, this would be a problem because lists2[1] is a MyObject. 

(I'm writing this syntax from memory and don't recall Swift's actual semantics when assigning collections to variables, but hopefully this points out the issue.)

like image 199
Michael Welch Avatar answered Dec 04 '25 00:12

Michael Welch



Donate For Us

If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!