Disclaimer: I'm still learning about the generics system. The following text is likely to be very confused and possibly has a simple solution
Howdy,
Given a code that looks roughly like this
protocol EntityState {}
protocol Entity {
associatedtype State: EntityState
var state: State { get set }
}
I would like to instantiate and configure a generic object using an any Entity
. e.g.
extension Entity {
static let all: [any Entity] = [...]
}
final class EntityViewController<EntityType: Entity>: UIViewController {
...
}
// I would like to be able to do something like this
let targetEntity = Entity.all.first!
let vc = EntityViewController(targetEntity) // EntityViewController<...>
I've noticed through experimentation that opening seems to fail with a compiler error in the following two cases:
- When the function that is to do the opening uses the type's generic directly ("Type 'any Enitity' does not conform to 'Enity'").
- When the function that is to do the opening returns a concrete type (nonzero exit code?)
If these are even real limitations, then they eliminate the following possibilities for a function that "instantiate(s) and configure a generic object using an any Entity".
final class EntityViewController<EntityType: Entity>: UIViewController {
// .init(targetEntity) Fails because 1 & 2
init(_ entity: EntityType) {...}
// .init(targetEntity) Fails because of 2. and even if it worked, it gives a scary warning that I'll get back to later.
init<InitEnityType>(_ entity: InitEntityType) where EntityType == InitEntityType {...}
// .makeAndConfigure(basedOn: targetEntity) Fails because 1 & 2
static func makeAndConfigure(basedOn entity: EntityType) -> Self {...}
// .makeAndConfigure(basedOn: targetEntity) Fails because of 1
static func makeAndConfigure(basedOn entity: EntityType) -> UIViewController {...}
// .makeAndConfigure(basedOn: targetEntity) Fails because of 2 (also gives scary warning)
static func makeAndConfigure<InitEnityType>(basedOn entity: InitEnityType) -> Self where EntityType == InitEntityType {...}
}
I believe this leaves me with one remaining option for creating an initializer-like function that can open an any Entity (while remaining in EntityViewController's namespace and maintaining type inference).
// Swap 'Self' on the last example for 'UIViewController'
final class EntityViewController<EntityType: Entity>: UIViewController {
static func makeAndConfigure<InitEnityType>(basedOn entity: InitEnityType) -> UIViewController where EntityType == InitEntityType {...}
}
Good news! This works.
let targetEntity = Entity.all.first!
✅ let vc = EntityViewController.makeAndConfigure(basedOn: targetEntity) // EntityViewController<...>
Bad news! I get something like this in the console.
Same-type requirement makes generic parameters 'InitEntityType' and 'EntityType' equivalent; this is an error in Swift 6
Which I guess makes sense, but its not good!
If possible I would like to implement an interface with a similar shape that won't break. Anyone got any advice?
Thanks,
smkuehnhold