CocoaUser
CocoaUser

Reputation: 1429

"Generic parameter 'T' could not be inferred" error in Swift

I am trying to practice "class with generic". I encountered 2 errors:

Generic parameter 'T' could not be inferred
Reference to generic type 'GenericObject' requires arguments in <...>

The 2 errors in GenericManager class. Please reference the following code. How do I solve this issue?

class User {
    var name: String
    init(name: String) {
        self.name = name
    }
}

class Employee {
    var name: String
    var position: String
    init(name: String, position: String) {
        self.name = name
        self.position = position
    }
}

class GenericObject<T> {
    var items = [T]()
    init(forType: T.Type) {}

    func addObject(_ obj: T) {
        self.items.append(obj)
    }
}

class GenericManager {
    //issue: Generic parameter 'T' could not be inferred
    var objects = [GenericObject]()        

    //issue: Reference to generic type 'GenericObject' requires arguments in <...>
    func addObject(_ obj: GenericObject) {
        self.objects.append(obj)
    }
}

let u = User(name: "User")
let uo = GenericObject(forType: User.self)
uo.addObject(u)


let e = Employee(name: "Employee", position: "session manager")
let eo = GenericObject(forType: Employee.self)
eo.addObject(e)

let manager = GenericManager()
manager.addObject(uo)
manager.addObject(eo)

Upvotes: 0

Views: 1853

Answers (2)

Oliver Atkinson
Oliver Atkinson

Reputation: 8029

The problem you are having is that you are trying to use generics, but want to ignore that in GenericManager and store references to objects of different types.

Consider this - when you call manager.objects[0] what would you expect to be returned?

You can solve this by type-erasure using Any as EmilioPelaez suggested. However this is often a codesmell which leads to casting hacks throughout your code.

One alternative would be to use an enum to specify the different types of data you want to represent:

enum GenericObject {
    case users([User])
    case employees([Employee])
}
...
let uo = GenericObject.users([ u ])
...
let eo = GenericObject.employees([ e ])

Now when you access the properties inside GenericManager you would be required to switch over the different supported types, and when you add a new type you would be required to implement code whenever you use a GenericObject

Upvotes: 0

EmilioPelaez
EmilioPelaez

Reputation: 19882

The compiler needs to know the type of T, and in this case you haven't supplied it.

You can do it like this:

var objects = [GenericObject<YourTypeHere>]()

For example, if GenericObject will hold an array of Int, it would look like this:

var objects = [GenericObject<Int>]()

I noticed you updated your question. It would be helpful to know what you're trying to achieve, but I'll try to help you anyway.

When you have a generic object, you need to tell the compiler the type of the generic at compile time, that's why it's complaining that the type can't be inferred, it needs to know.

Since you want to be able to add objects to the GenericManager array, you need the generic in those two cases to be the same, so you can modify your class like this:

class GenericManager<T> {
    var objects = [GenericObject<T>]()

    func addObject(_ obj: GenericObject<T>) {
        self.objects.append(obj)
    }
}

However, since the objects have to be of the same generic, you can't add a GenericObject<User> and GenericObject<Employee> to the same manager, what you can do is to implement those as GenericObject<Any>, and do the same with the GenericManager, then it will look like this:

let u = User(name: "User")
let uo = GenericObject(forType: Any.self)
uo.addObject(u)


let e = Employee(name: "Employee", position: "session manager")
let eo = GenericObject(forType: Any.self)
eo.addObject(e)

let manager = GenericManager<Any>()
manager.addObject(uo)
manager.addObject(eo)

Keep in mind that this will lose you any advantage that generics would do, what you could do is to create a protocol or common superclass and use that instead of Any, but that depends on what you're trying to achieve.

If you have any further questions, please add a comment instead of silently updating your question.

Upvotes: 2

Related Questions