Conformité facultative au protocole Swift via non facultative

Aug 18 2020

J'ai un protocole avec une propriété facultative.

La plupart des types conformes à ce protocole auront une propriété facultative correspondante. Cependant, on a une propriété non facultative du même type et du même nom.

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'
}

En appuyant sur "Fix - Voulez-vous ajouter des talons de protocole ?" de Xcode. ajoute la version facultative de la propriété, mais la structure contient désormais des noms de variables en double non valides :

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

Dans le { get }seul cas, j'avais supposé que cela "fonctionnerait simplement" car le non-facultatif satisfaisait toujours les contraintes du facultatif, de la même manière que vous pouvez renvoyer un non-facultatif dans une fonction avec un type de retour facultatif. Mais apparemment ce n'est pas le cas.

Cela fonctionne de la même manière pour les fonctions ; un protocole func bar() -> Int?n'est pas satisfait par un type conforme déclarant func bar() -> Int.

Existe-t-il un moyen de contourner ce problème ? Je préférerais ne pas renommer les variables ou ajouter des getters intermédiaires.

Cette situation a-t-elle été envisagée pour Swift ? Quelle est la raison de ne pas autoriser un non-facultatif à satisfaire une variable de protocole facultative ?

Réponses

pkamb Aug 19 2020 at 00:34

Si le protocole fournit une implémentation par défaut qui renvoie un facultatif :

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

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

les types conformes au protocole peuvent alors fournir une version prioritaire non optionnelle de la variable/fonction :

struct StructB: SomeProtocol {
    let foo: Int
}

J'ai trouvé ceci discuté sur le forum Swift Evolution:

À première vue, je pensais qu'il existait une règle qui nous permettait de satisfaire aux exigences du protocole avec des types non facultatifs, mais cela a entraîné une erreur. Ce n'est qu'après une enquête plus approfondie que j'ai remarqué qu'une implémentation par défaut doit exister afin de « en quelque sorte remplacer » l'exigence avec une version non facultative.

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

Cette équipe Swift discute également de l'autorisation de types non facultatifs pour satisfaire les protocoles à valeur facultative :

Cela aurait-il un sens d'autoriser la satisfaction des exigences de protocole avec des types non facultatifs, comme avec des init faillibles ? (Probablement avec une promotion optionnelle implicite.)

Ouais, totalement ! À l'exception de la partie où cela modifie le comportement du code existant, nous devons donc être très prudents à ce sujet. Ceci est considéré comme faisant partie de [SR-522] Les fonctions de protocole ne peuvent pas avoir de retours covariants

qui est suivi sur Stack Overflow ici :

Pourquoi une exigence de propriété get-only dans un protocole ne peut-elle pas être satisfaite par une propriété conforme ?