Hello everyone, I have a type like this and I want the Model and ObjectProtocol to be strongly bound:
final public class Model<Object> where Object: ObjectProtocol {
var object: Object
public init(object: Object) {
self.object = object
}
}
And I would like to use Model like this:
protocol SubObjectProtocol: ObjectProtocol {
var name: String { get }
}
let model: Model<SubObjectProtocol> = ..... // error: Type 'any SubObjectProtocol' cannot conform to 'ObjectProtocol'
I can only use some ObjectProtocol to initialize the Model, but I can't bind the generic Object with some ObjectProtocol.
final public class Model<Object> {
var object: Object
public init(object: some ObjectProtocol) { // No idea how to bind
self.object = object // error: Cannot assign value of type 'some ObjectProtocol' to type 'Object'
}
}
As @ibex mentioned, you cannot pass in a protocol where a concrete type is expected.
If I understand the question correctly you want the generic Object to be constrained to only concrete types that conform to the SubObjectProtocol ? In that case, you could replace
public protocol ObjectProtocol {
var some: String {get set}
}
public protocol SubObjectProtocol: ObjectProtocol {
var name: String { get }
}
final public class Model<Object> where Object: ObjectProtocol {
var object: Object
public init(object: Object) { // No idea how to bind
self.object = object
}
func checkMe() {
print ("\(object.some)") // Protocol has it
switch object {
case is RootObject: print ("Root has no name")
case is SubObject: if let sub = object as? SubObject {
print ("I have name: \(sub.name)")
}
default: print ("I don'y know who I'm")
}
}
}
struct RootObject: ObjectProtocol {
var some = "I'm Root"
}
struct SubObject: SubObjectProtocol {
var some = "I'm Sub"
var name = "Kornelius Rep"
}
let rootObject: RootObject = RootObject()
let subObject: SubObject = SubObject()
let z = Model(object: rootObject)
let s = Model(object: subObject)
z.checkMe()
s.checkMe()
final public class Model2 {
var object: ObjectProtocol
public init(object: some ObjectProtocol) { // No idea how to bind
self.object = object
}
func checkMe() {
print ("\(object.some)") // Protocol has it
switch object {
case is RootObject: print ("Root has no name")
case is SubObject: if let sub = object as? SubObject {
print ("I have name: \(sub.name)")
}
default: print ("I don'y know who I'm")
}
}
}
let z1 = Model2(object: rootObject)
let s1 = Model2(object: subObject)
z1.checkMe()
s1.checkMe()
///------ OR ---------
final public class Model2 {
var object: ObjectProtocol
public init(object: some ObjectProtocol) { // No idea how to bind
self.object = object
}
func checkMe() {
print ("\(object.some)") // Protocol has it
switch object {
case is RootObject: print ("Root has no name")
case is SubObject: if let sub = object as? SubObject {
print ("I have name: \(sub.name)")
}
default: print ("I don'y know who I'm")
}
}
}
let z1 = Model2(object: rootObject)
let s1 = Model2(object: subObject)
z1.checkMe()
s1.checkMe()
Hi @NotTheNHK SubObjectProtocol here can be any type that inherits from ObjectProtocol.
I need ObjectProtocol for Model to satisfy certain requirements, and I need to implement the type for SubObjectProtocol in another package, so it is better for it to be a protocol.
The place where I create the Model object and the place where I implement RootObject/SubObject are in different packages, so I have to use ObjectProtocol/SubObjectProtocol to define the Model type.
As I said before, I can't obtain the actual implementation type of ObjectProtocol where I use Model, so I can't use RootObject from your code to create Model.
@miku1958 This should be a good basis for the rest of Model<Object>.
final public class Model<Object> where Object : ObjectProtocol {
var object: Object
public init(object: Object) {
self.object = object
}
/// Nillable as ``ObjectProtocol`` cannot be guaranteed to be exclusively ``Object``
/// - Note: Performs ``init(object: Object)`` after coercing `object`
/// - Parameter object: Value that should be the same type as ``Object``. `Object` is always contained in `some ObjectProtocol`
/// - Returns: `nil` is provided when `object.Type` isnât ``Object``
public convenience init?(object: ObjectProtocol) {
guard let object: Object = object as? Object else { return nil }
self.init(object: object)
}
}
You can freely change the type of object in the nillable initializer between some and any. It depends on context if it should be abstract generic or specialized generic.
You can use the provided Model.init?(object:) like so:
guard let demoModel = Model<ParticularConformingType>(object: ConformingType()) else {
expectationFailure(â`demoModel.object` wasnât the expected type \(ParticularConformingType.Type)â)
}