protocol medium extension example delegate and swift inheritance protocols

swift - medium - ¿Cómo se implementan los métodos de protocolo que devuelven Selfs covariantes?



swift protocol and delegate example (2)

Como dice, no puedes hacer esto, y por una buena razón. No puedes demostrar que mantendrás tu promesa. Considera esto:

class AnotherSubclass: Class {} let x = AnotherSubclass().instance

Entonces x debería ser AnotherSubclass según su protocolo (eso es Self ). Pero en realidad será Subclass , que es un tipo completamente diferente. No puedes resolver esta paradoja a menos que la clase sea final . Esta no es una limitación Swift. Esta limitación existiría en cualquier sistema de tipo correcto porque permite una contradicción de tipo.

Por otro lado, algo que puede hacer es prometer que la instance devuelve algún tipo consistente en todas las subclases (es decir, la superclase). Lo haces con un tipo asociado:

protocol Protocol { typealias InstanceType var instance: InstanceType {get} } class Class: Protocol { var instance: Class {return Subclass()} } class Subclass: Class {} class AnotherSubclass: Class {} let x = AnotherSubclass().instance

Ahora x es inequívocamente de tipo Class . (También sucede que es al azar otra subclase, lo cual es un poco raro, pero eso es lo que dice el código).

Por cierto, todo esto generalmente sugiere que estás usando subclases cuando realmente no deberías. La composición y los protocolos probablemente resolverían mejor este problema en Swift. Pregúntese si existe algún motivo por el cual la Subclass necesite ser realmente una subclase de la Class . ¿Podría ser un tipo independiente que se ajuste al mismo protocolo? Todo tipo de problemas desaparecen cuando te deshaces de las subclases y te enfocas en los protocolos.

He estado pensando en esto más, y puede haber una manera de obtener lo que estás buscando. En lugar de decir que todas las subclases implementan la instance , adjunte la instance como una extensión. Todavía puede anular eso si desea devolver algo más.

protocol Protocol { init() } class Class: Protocol { required init() {} var instance: Class { return Subclass() } } extension Protocol { var instance: Self { return self.dynamicType.init() } } class Subclass: Class {}

Esto esquiva el problema de la herencia (no se puede crear el mismo " AnotherClass devolviendo el tipo incorrecto" de esta manera).

error: protocolo ''Protocolo'' requisito ''instancia'' no puede ser satisfecho por una clase no final (''Clase'') porque usa ''Auto'' en una posición sin parámetro, sin resultado

protocol Protocol { var instance: Self {get} } class Class: Protocol { var instance: Class {return Subclass()} } class Subclass: Class {}

Así es como expresaría lo que quiero, en C #. (C # no tiene, según mi conocimiento, una forma de exigir que el parámetro genérico "Self" sea en realidad el Self que conocemos de Swift, pero funciona lo suficientemente bien como documentación que debería hacerme hacer lo correcto).

interface Protocol<Self> where Self: Protocol<Self> { Self instance {get;} } class Class: Protocol<Class> { public Class instance {get {return new Subclass();}} } class Subclass: Class {}

... cómo podría verse en una versión futura de Swift:

protocol Protocol { typealias FinalSelf: Protocol where FinalSelf.FinalSelf == FinalSelf var instance: FinalSelf {get} } class Class: Protocol { var instance: Class {return Subclass()} } class Subclass: Class {}

Cómo estoy emulando la parte de eso que es relevante para mi problema:

protocol Protocol: ProtocolInstance { static var instance: ProtocolInstance {get} } protocol ProtocolInstance {} class Class: Protocol { static var instance: ProtocolInstance {return Subclass()} } class Subclass: Class {}

Y, aquí está lo que creo que es la parte relevante de mi código:

protocol Protocol { static var 🎁: Self? {get} // an existing instance? static var 🐥: Self {get} // a new instance func instanceFunc() } extension Protocol { static func staticFunc() { (🎁 ?? 🐥).instanceFunc() } }


Esto realmente tendría sentido y funcionaría si no quieres regresar a Self para cada subclase como esta:

protocol Protocol : class { typealias Sub : Self var instance: Sub {get} }

Lo que significa que su protocolo define un typealias que tiene que ser una subclase de sí mismo. El siguiente código simplemente funcionaría:

class Class: Protocol { var instance: Class {return Subclass()} } class Subclass: Class {} Class().instance // Returns SubClass()

Sin embargo, el código anterior no se compila con el error

error: inheritance from non-protocol, non-class type ''`Self`''

que creo que es un error, porque Self se declara como un tipo de clase. Sin embargo, puedes hacer que funcione de alguna manera como este:

protocol Protocol : class { typealias Sub : Class var instance: Sub {get} }

pero entonces no tiene mucho del protocolo en sí mismo porque solo la clase en sí misma debería conformarse a él.