iliasaz
(Ilia Sazonov)
1
Hi All,
Please consider the following example. I have two Entity classes both conforming to Model protocol. I'd like to take a certain action, which implementation depends on a specific entity type. For example, I'd like to JSON-encode the entity. For the sake of simplicity in this example I just print its type.
import Foundation
protocol Model {}
class Entity1 : Model {}
class Entity2 : Model {}
class Stub : Model {}
func getModelType<T: Model>(typeName: String) -> T.Type {
switch typeName {
case "e1":
return Entity1.self as! T.Type
case "e2":
return Entity2.self as! T.Type
default: return Stub.self as! T.Type
}
}
let t = getModelType(typeName: "e1")
if t == Entity1.Type { print("Entity 1") }
else { print("Not Entity 1") }
I'm getting "Generic parameter 'T' could not be inferred" error in this line:
let t = getModelType(typeName: "e1")
Is there any workaround?
Thanks!
Alejandro
(Alejandro Alonso)
2
So your usage of generics in this function don't quite make sense because the caller can do something like:
let t: Stub.Type = getModelType(typeName: "e1")
which will result in a runtime failure. The reason you get the error that T couldn't be inferred is that there is no caller information on what this T type is, hence the reason one needs to add : SomeType.Type to the variable declaration. I believe you may want something like the following instead:
func getModelType(typeName: String) -> Model.Type { /* ... */ }
let t = getModelType(typeName: "e1")
if t == Entity1.self { /* ... */ }
where now we're returning some metatype whose base conforms to Model
iliasaz
(Ilia Sazonov)
3
Thanks for your comment, and your example certainly makes sense. Let's take it one step further. The Model is actually a Vapor Model protocol, and it comes with some restrictions. The issue now is
Protocol 'Model' can only be used as a generic constraint because it has Self or associated type requirements
I kinda understand the meaning, and this post explains is quite well... But how do I implement this seemingly simple and common pattern?
class Entity1 : Model {
var id: String?
typealias IDValue = String
}
class Entity2 : Model {
var id: String?
typealias IDValue = String
}
class Stub : Model {
var id: String?
typealias IDValue = String
}
func getModelType(typeName: String) -> Model.Type { // <<< New Error
switch typeName {
case "e1":
return Entity1.self
case "e2":
return Entity2.self
default: return Stub.self
}
}
let t = getModelType(typeName: "e1")
if t == Entity1.self { print("Entity 1") }
else { print("Not Entity 1") }