Protocolo Swift Conformidad opcional a través de Non-Optional

Aug 18 2020

Tengo un protocolo con una propiedad opcional.

La mayoría de los tipos que se ajustan a este protocolo tendrán una propiedad opcional coincidente. Sin embargo, uno tiene una propiedad no opcional del mismo tipo y nombre.

protocol SomeProtocol {
    var foo: Int? { get }
}

struct StructA: SomeProtocol {
    let foo: Int?
}

struct StructB: SomeProtocol {
    let foo: Int // Type 'StructB' does not conform to protocol 'SomeProtocol'
}

Presionando "Reparar - ¿Quieres agregar stubs de protocolo?" de Xcode El botón agrega la versión opcional de la propiedad, pero la estructura ahora tiene nombres de variables duplicados no válidos:

struct StructB: SomeProtocol {
    let foo: Int
    var foo: Int? { return foo } // Invalid redeclaration of 'foo'
}

En el { get }único caso, asumí que esto "simplemente funcionaría" debido a que lo no opcional siempre satisface las restricciones de lo opcional, similar a cómo puede devolver un no opcional en una función con un tipo de retorno opcional. Pero al parecer ese no es el caso.

Esto funciona igual para las funciones también; un protocolo func bar() -> Int?no se satisface con un tipo conforme que declara func bar() -> Int.

¿Hay alguna forma de solucionar este problema? Preferiría no cambiar el nombre de las variables ni agregar captadores intermedios.

¿Se ha considerado esta situación para Swift? ¿Cuál es la razón para no permitir que una variable no opcional satisfaga una variable de protocolo opcional?

Respuestas

pkamb Aug 19 2020 at 00:34

Si el protocolo proporciona una implementación predeterminada que devuelve un opcional:

protocol SomeProtocol {
    var foo: Int? { get }
}

extension SomeProtocol {
    var foo: Int? { return nil }
}

Los tipos que cumplen con el protocolo pueden proporcionar una versión superior no opcional de la variable/función:

struct StructB: SomeProtocol {
    let foo: Int
}

Encontré esto discutido en el foro de Swift Evolution:

A primera vista, pensé que había una regla que nos permite satisfacer los requisitos del protocolo con tipos no opcionales, pero esto resultó en un error. Solo después de una mayor investigación, noté que debe existir una implementación predeterminada para "anular" el requisito con una versión no opcional.

https://forums.swift.org/t/how-does-this-rule-work-in-regard-of-ambiguity/19448

Este equipo de Swift también analiza permitir que los tipos no opcionales satisfagan los protocolos de valor opcional:

¿Tendría algún sentido permitir la satisfacción de requisitos de protocolo con tipos no opcionales, como con inicios fallidos? (Probablemente con alguna promoción opcional implícita).

¡Sí, totalmente! Excepto por la parte en la que esto cambia el comportamiento del código existente, por lo que debemos tener mucho cuidado al respecto. Esto se considera parte de [SR-522] Las funciones del protocolo no pueden tener retornos covariantes

que se rastrea en Stack Overflow aquí:

¿Por qué un requisito de propiedad de solo obtener en un protocolo no puede ser satisfecho por una propiedad que cumple?