swift - multiple - ¿Por qué una propiedad que cumple no puede satisfacer un requisito de propiedad de solo obtención en un protocolo?
protocolos swift (1)
No hay una razón real por la que esto no sea posible, un requisito de propiedad de solo lectura
puede
ser covariante, ya que devolver una instancia de
ConformsToB
desde una propiedad escrita como
ProtocolB
es perfectamente legal.
Swift actualmente no lo admite.
Para hacerlo, el compilador tendría que generar
un enlace
entre la tabla testigo del protocolo y la implementación conforme para realizar las conversiones de tipo necesarias.
Por ejemplo, una instancia de
ConformsToB
debería estar
encuadrada
en un contenedor existencial
para ser escrita como
ProtocolB
(y no hay forma de que la persona que llama pueda hacer esto, ya que podría no saber nada sobre la implementación que se llama).
Pero, de nuevo, no hay razón para que el compilador no pueda hacer esto. Hay varios informes de errores abiertos sobre esto, este es específico para los requisitos de propiedad de solo lectura, y este general , en el que Slava Pestov, miembro del equipo Swift, dice:
[...] queremos testigos de protocolo y anulaciones de métodos en todos los casos en que se permite una conversión de funciones
Por lo tanto, definitivamente parece algo que el equipo de Swift está buscando implementar en una versión futura del lenguaje.
Sin embargo, mientras tanto, como
dice @BallpointBen
, una solución alternativa es usar un tipo
associatedtype
:
protocol ProtocolA {
// allow the conforming type to satisfy this with a concrete type
// that conforms to ProtocolB.
associatedtype SomeProperty : ProtocolB
var someProperty: SomeProperty { get }
}
protocol ProtocolB {}
class ConformsToB: ProtocolB {}
class SomeClass: ProtocolA {
// implicitly satisfy the associatedtype with ConformsToB.
var someProperty: ConformsToB
init(someProperty: ConformsToB) {
self.someProperty = someProperty
}
}
Pero esto es bastante insatisfactorio, ya que significa que el
ProtocolA
ya no se puede usar como tipo (porque tiene requisitos de tipo
associatedtype
).
También cambia lo que dice el protocolo.
Originalmente decía que
someProperty
podía devolver
cualquier cosa
que se ajustara al
ProtocolB
someProperty
; ahora dice que una implementación de
someProperty
trata solo de un tipo concreto
específico
que se ajusta al
ProtocolB
someProperty
Otra solución es solo definir una propiedad ficticia para satisfacer el requisito del protocolo:
protocol ProtocolA {
var someProperty: ProtocolB { get }
}
protocol ProtocolB {}
class ConformsToB: ProtocolB {}
class SomeClass: ProtocolA {
// dummy property to satisfy protocol conformance.
var someProperty: ProtocolB {
return actualSomeProperty
}
// the *actual* implementation of someProperty.
var actualSomeProperty: ConformsToB
init(someProperty: ConformsToB) {
self.actualSomeProperty = someProperty
}
}
Aquí estamos esencialmente escribiendo el thunk para el compilador, pero tampoco es particularmente bueno ya que agrega una propiedad innecesaria a la API.
¿Por qué el siguiente código produce un error?
protocol ProtocolA {
var someProperty: ProtocolB { get }
}
protocol ProtocolB {}
class ConformsToB: ProtocolB {}
class SomeClass: ProtocolA { // Type ''SomeClass'' does not conform to protocol ''ProtocolA''
var someProperty: ConformsToB
init(someProperty: ConformsToB) {
self.someProperty = someProperty
}
}
La respuesta en esta pregunta similar tiene sentido. Sin embargo, en mi ejemplo, la propiedad es get-only. ¿Por qué no debería funcionar esto? ¿Es una deficiencia de Swift, o hay alguna razón por la que esto tiene sentido?