5 buoni motivi per usare le structs in Swift

Se siete degli sviluppatori iOS e avete iniziato nel periodo pre-Swift (cioè prima del 2014) avete programmato in Objective-C e quindi probabilmente conoscete il vecchio concetto di struct. Si tratta di un costrutto che Objective-C eredita da C e che ci permette di raggruppare una serie di campi in un unico tipo di dato.

Tuttavia il concetto di classe era molto più potente (e complesso!) e quasi sempre veniva preferito dagli sviluppatori. Alcuni linguaggi poi, come Java, hanno puntato totalmente sulle classi decidendo di non contemplare assolutamente il costrutto struct.

Personalmente mi aspettavo una scelta simile per Swift, eppure nel Giugno del 2014, poco dopo aver iniziato a leggere la documentazione mi sono reso conto che Swift punta tantissimo sulle struct e in determinati casi le privilegia rispetto alle classi nell’intenzione di offrire allo sviluppatore dei paradigmi di programmazione che vadano oltre la programmazione a oggetti (vedi Protocol Oriented Programming) e che siano più in linea con la Functional Programming (che dopo oltre mezzo secolo stiamo finalmente iniziando a sfruttare seriamente).

Cosa è una struct in Swift?

Una struct permette di definire un tipo. La definizione di una struct può contenere

  1. metodi
  2. properties
  3. initializers
  4. e infine può essere conforme a un certo numero di protocolli

Ma soprattutto una struct è un value type e non un reference type (maggiori info qui).

Quali vantaggi ha una struct rispetto a una classe?

Una struct è sottoposta a molte più limitazioni rispetto a una classe e in determinati scenari questo ne rappresenta i punti di forza. Negli ultimi anni Apple sta convertendo molte classi centrali di Cocoa (come NSString, NSArray, NSDictionary, NSSet, NSURL, …) in altrettante struct (String, Array, Dictionary, Set, URL). Vediamo i punti di forza di una struct rispetto a una classe.

1) Una struct è un value type

Già detto 2 paragrafi fa ma è fondamentale che questo concetto sia chiaro.

strategy

Con una classe posso avere n variabili che referenziano lo stesso oggetto

Con una struct questo non accade

Questo significa che usando una struct riduciamo drasticamente il rischio che altre porzioni del codice stiano modificando in concorrenza il nostro valore mentre lo stiamo accedendo.

2) La struct è più veloce di una classe

I valori di una struct vengono salvati nello stack mentre gli oggetti delle classi nell’heap (o free space). Lo stack è un area di memoria più veloce e spesso viene addirittura rappresentata nella memoria interna della CPU.

stopwatch

3) La struct ha il memberwise initializer

Torniamo al codice precedente

Quando in una struct non definiamo un initializer, di default viene fornito il memberwise initializer, ovvero un initializer che provvede a inizializzare tutte le properties.

checklistQuindi se aggiorniamo la struct Person come segue

viene attivato in automatico il memberwise initializer che ci permette di scrivere

Ovviamente aggiungendo una property alla struct, viene automaticamente richiesto un nuovo parametro dall’initializer

4) Con la struct l’immutability è integrata

Ricordate che in Objective-C esistevano (ed esistono tuttora) coppie di classi per rappresentare lo stesso concetto? Ad esempio NSArray e NSMutableArray, NSDictionary e NSMutableDictionary e così via…

safe

L’idea di Cocoa era di fornire 2 versioni della stessa classe, una mutabile e una immutabile. Con le struct questo concetto acquisisce un’importanza centrale ed è gestito in modo più elegante. Vediamo il seguente esempio: creiamo un valore di tipo Person e salviamolo in una variabile.

Abbiamo appena creato un valore mutabile, infatti è possibile assegnare un nuovo valore alla property name.

Al contrario se creiamo un valore di tipo Person e lo assegniamo a una costante creiamo un valore immutabile.

Come vedete nell’esempio precedente un tentativo di modifica della property viene segnalato come un errore. E’ importante notare che il concetto di costante assume un significato molto più profondo per i value type.

Infatti mentre nel caso della classi (reference type) una costante ha effetto sulla referenza alla classe ma permette tranquillamente di cambiare i valori assegnati alle properties.

Invece nel caso delle struct (value type) una costante ha l’effetto di bloccare la modifica delle sue properties.

metodi mutating

Ricorderete che la classe NSMutableArray offriva anche dei metodi aggiuntivi rispetto alla controparte NSArray. Ritroviamo questo concetto anche nelle struct. Infatti se vogliamo definire un metodo che modifichi una valore di una property dobbiamo espressamente annotare quel metodo come mutating.

I metodi mutating sono disponibili quando il valore di una struct è salvato in una variabile

Quindi il seguente codice compila senza problemi

Mentre se usiamo una costante otteniamo un errore perché hide non è disponibile

5) La struct NON ha ereditarietà

La OOP funziona bene per domini di dati concettualmente gerarchici.

Ma è piuttosto inefficiente (soprattutto quella con ereditarietà singola) a rappresentare relazioni di concetti più complesse.

512_plant

Osservate il seguente codice

A questo punto la classe Crocodile non può estendere Quadruped perché non è un Mammal. Potete provare a riorganizzare il codice a piacimento ma il problema non si risolve.

A meno che non vogliate introdurre i protocolli (le interfacce di Java).  Ecco le struct vi obbligano a usare soltanto protocolli. Questo rende il codice estremamente più chiaro e semplice.

Conclusione

E’ quindi giunto il momento di buttare dalla finestra il concetto di classe e l’intera programmazione orientata agli oggetti? No, non ancora. Ci sono tanti scenari in cui la OOP svolge egregiamente il suo lavoro. Basti guardare la maggior parte delle classi di UIKit (UIViewController, UITableViewController, etc…) o di SpriteKit o anche SceneKit. Buona parte dei framework di iOS (ma anche macOS, watchOS e tvOS) sono costruiti intorno al concetto di classe e di ereditarietà.

Lo scopo di questo articolo è semplicemente quello di mettere in luce uno degli strumenti principali della POP (Protocol Oriented Programming) e della Functional Programming perché il futuro dello sviluppo sulle piattaforme Apple punta verso questi 2 paradigmi.

Luca Angeletti

Trainer • Developer • Writer

Lascia un commento

Il tuo indirizzo email non sarà pubblicato. I campi obbligatori sono contrassegnati *