Storia della questione:
I tipi opachi (some) sono stati introdotti con Swift 5.1 e hanno aperto un nuovo modo di astrarre il valore di ritorno di una funzione o proprietà, quando il tipo è conosciuto dal compilatore, ma nascosto all'utente. Questa è un'alternativa agli esistenziali dei protocolli (any Protocol), ma con un legame rigido a un tipo concreto all'interno della funzione.
Problema: Quando una funzione restituisce un protocollo con associatedtype (ad esempio, Sequence), non è possibile scrivere direttamente:
func makeNumberSequence() -> Sequence { ... } // errore
Gli esistenziali dei protocolli consentono di restituire qualsiasi implementazione, ma non garantiscono lo stesso tipo ad ogni chiamata:
func foo() -> any View { ... }
Questo porta all'imprevedibilità e a una scarsa sicurezza dei tipi.
Soluzione: Utilizzare il tipo di risultato opaco:
func makeNumbers() -> some Sequence { [1, 2, 3] }
Ora il compilatore conosce esattamente il tipo di ritorno effettivo, ma è nascosto all'esterno. Questo permette ottimizzazioni delle prestazioni, sicurezza, consente di utilizzare il DSL di SwiftUI e facilita lo scambio di tipi tra i moduli.
Caratteristiche chiave:
Possono i tipi opachi essere utilizzati per memorizzare un valore (come le proprietà di una classe)?
No. I tipi opachi si applicano solo ai valori di ritorno di funzioni o alle proprietà calcolate. Per memorizzare un valore o un array di valori si usano gli esistenziali (any Protocol).
Possono diversi rami di una stessa funzione restituire tipi diversi con some?
No. Il compilatore richiede che entrambi (o tutti) i rami restituiscano lo stesso tipo concreto; altrimenti, ci sarà un errore:
func foo(flag: Bool) -> some Sequence { if flag { return [1, 2, 3] } else { return ["a", "b", "c"] // errore } }
È possibile usare some per identificare il tipo di ritorno tra più funzioni?
No. Ogni funzione con some restituisce il proprio tipo nascosto unico, anche se in effetti si tratta dello stesso array. Non è possibile utilizzare il risultato di una funzione come parametro in un'altra, se entrambe utilizzano some con protocolli diversi o tipi nascosti diversi.
Nel progetto tutto viene restituito tramite any Protocol, le collezioni perdono la tipizzazione, si verificano bug durante il downcast, rallenta l'ottimizzazione dei tempi di compilazione.
Pro:
Contro:
Nella progettazione SwiftUI, i componenti restituiscono some View, ogni modulo definisce chiaramente il tipo interno. La dimensione del bundle si riduce, la compilazione si accelera.
Pro:
Contro: