Esistono generalmente due tipi di framework di raccolta: quelli senza codice duplicato ma che perdono il tipo di raccolta e quelli che conservano il tipo di raccolta ma hanno il codice duplicato.
La maggior parte rientra nel primo campo, ad es. in .NET, tutto restituisce IEnumerable
, in Ruby, tutto restituisce Array
, in Python, tutto restituisce un iterabile, ecc. Smalltalk cade nel secondo campo: tutte le operazioni preservano il tipo, ma a costo di duplicare semplicemente il operazioni per ogni tipo.
Scala ha la prima libreria di collezioni su larga scala che conosco che riesce a preservare il tipo senza duplicazioni. L'idea chiave è il concetto di builder , che sono oggetti che sanno come (in modo efficiente) creare collezioni di un tipo specifico. Quindi, un'operazione come filter
ha solo bisogno di cercare il builder per il tipo di raccolta e quindi può usare questo builder per creare in modo efficiente la raccolta dei risultati senza dover conoscere in realtà ogni singola raccolta che potrebbe mai esistere. In Scala, è il sistema di tipi (o più precisamente risoluzione implicita ) che si occupa di questa ricerca in fase di compilazione (in modo che non vi sia sovraccarico di runtime), ma può anche essere fatto in fase di runtime.
Si noti, tuttavia, che le operazioni di raccolta di preservazione dei tipi possono avere conseguenze sorprendenti. Ad esempio, non ti aspetti che map
cambi la lunghezza di una raccolta, ma
map(Set(1, 2, 3, 4), lambda el: is_even(el)) == Set(true, false)
Inoltre, in alcuni casi, devi effettivamente restituire un tipo più generale o un altro tipo correlato. Ad esempio, un ByteSet
può contenere solo i numeri 1-255, quindi
map(ByteSet(16), lambda el: el.__str__()) == Set("16")
map(ByteSet(16), lambda el: el ** 2) == IntSet(256)
Quindi, se vuoi creare un framework di collezioni di preservazione dei tipi, puoi guardare il framework delle collezioni di Scala e i suoi builder e il CanBuildFrom
macchinario implicito di tipo. Ti suggerirei di guardare la proposta di Strawman per la struttura semplificata e ridisegnata in Scala 2.13 invece della versione attuale poiché quest'ultima è considerata eccessivamente ingegnerizzata e eccessivamente complessa.