Perché un requisito di proprietà get-only in un protocollo non può essere soddisfatto da una proprietà conforms?

Perché il seguente codice genera un errore?

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 risposta in questa domanda simile ha un senso. Tuttavia, nel mio esempio, la proprietà è get-only. Perché non dovrebbe funzionare? È una lacuna di Swift, o c’è qualche ragione per cui ciò ha un senso?

Non c’è una vera ragione per cui questo non dovrebbe essere ansible, un requisito di proprietà di sola lettura può essere covariante, poiché restituire un’istanza ConformsToB da una proprietà digitata come ProtocolB è perfettamente legale.

Swift solo al momento non lo supporta. Per fare ciò, il compilatore dovrebbe generare un thunk tra la tabella dei testimoni del protocollo e l’implementazione conforms per poter eseguire le conversioni di tipi necessarie. Ad esempio, un’istanza ConformsToB dovrebbe essere racchiusa in un contenitore esistenziale per poter essere digitata come ProtocolB (e non è ansible che il chiamante possa farlo, in quanto potrebbe non sapere nulla sull’implementazione chiamata).

Ma ancora, non c’è motivo per cui il compilatore non dovrebbe essere in grado di farlo. Ci sono più segnalazioni di bug aperte su questo, questo è specifico per i requisiti di proprietà di sola lettura, e questo generale , in cui Slava Pestov, membro del team di Swift, dice:

[…] Vogliamo testimoni di protocollo e sostituzioni di metodi in tutti i casi in cui è consentita la conversione di una funzione

Quindi sembra decisamente qualcosa che il team di Swift sta cercando di implementare in una versione futura della lingua.

Nel frattempo però, come dice @BallpointBen , una soluzione alternativa è usare 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 } } 

Ma questo è abbastanza insoddisfacente, poiché significa che ProtocolA non è più utilizzabile come tipo (perché ha i requisiti associatedtype ). Cambia anche ciò che dice il protocollo. Originariamente affermava che someProperty poteva restituire qualsiasi cosa conforms a ProtocolB – ora si dice che un’implementazione di someProperty riguarda solo un tipo concreto specifico conforms a ProtocolB .

Un’altra soluzione è solo definire una proprietà fittizia per soddisfare il requisito del protocollo:

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

Qui stiamo essenzialmente scrivendo il thunk per il compilatore, ma non è particolarmente bello in quanto aggiunge una proprietà inutile all’API.