3 ragioni per smettere di scrivere cicli FOR

website-settingsIl ciclo FOR è un costrutto disponibile in molti linguaggi di programmazione con il quale possiamo definire un’iterazione che permette di eseguire ripetutamente un determinato blocco di codice.

Si tratta di un costrutto più moderno del GOTO ma che inizia a mostrare i segni dell’età, infatti le sue origini risalgono al lontano 1958 quando fu introdotto dal linguaggio ALGOL 58.

Swift, come molti linguaggi di programmazione, fornisce allo sviluppatore diverse varianti del ciclo FOR, eccone una:

Il blocco all’interno del FOR precedente viene ripetuto tante volte quanto il numero di elementi contenuti in numbers. Per ogni iterazione viene estratto da numbers l’elemento i-esimo e usato per incrementare la variabile sum.

Probabilmente se sei uno sviluppatore conosci bene e utilizzi frequentemente il ciclo for per evitare codice ripetuto e per impostare la ripetizione di un blocco un numero di volte che non è conosciuto a tempo di compilazione. Forse però non conosci le problematiche legate a questo approccio alla programmazione. Vediamole insieme.

1) Non è thread safe

Il blocco di codice precedente non è implicitamente thread safe. numbers potrebbe essere modificato da un secondo thread  con risultati dannosi per il nostro codice.

Ad esempio se un thread rimuovesse un elemento da numbers mentre il ciclo FOR è in esecuzione si genererebbe un fatal error appena il nostro codice tentasse di estrarre il terzo elemento di numbers (che ormai non esisterebbe più).

competition

2) Ci obbliga a usare valori mutabili

Nell’esempio precedente abbiamo dovuto creare la variabile sum in modo da poter sommare di volta in volta il contenuto di numbers. Ora, la maggior parte dei programmi contengono variabili ma questo non è necessariamente un bene… Le variabili permettono al compilatore di effettuare meno ottimizzazioni rispetto alle costanti, come visto in precedenza rischiano di essere modificate in modo imprevisto da un secondo thread e in generale sono meno sicure delle costanti. E si, è possibile scrivere del codice chiaro e sicuro senza l’utilizzo delle variabili, vedremo come fare tra poco.

3) Ci spinge a scrivere codice imperativo

Il codice che abbiamo visto ha come scopo quello di ottenere la somma di tutti i valori presenti in numbers. Si tratta di una porzione di codice molto semplice tuttavia lo abbiamo scritto indicando al compilatore i passi da eseguire per ottenere il risultato voluto. Esiste un’opzione migliore: scrivere codice che descriva il risultato voluto lasciando al compilatore l’onere di trovare un modo per ottenere quel risultato. I principali vantaggi di questa tecnica dichiarativa sono i seguenti:

strategy

  1. Meno codice.
  2. Codice più chiaro, in cui descriviamo le nostre necessità: questo si traduce in una minore probabilità di bug.
  3. Usando codice dichiarativo dobbiamo sfruttare alcune funzionalità del linguaggio (come map, reduce e filter) che probabilmente produrranno un compilato più efficiente di quello che potremo mai scriveremo noi (soprattutto se chi ha progettato il compilatore ha anche disegnato la CPU).
  4. Quando il fornitore del linguaggio o del compilatore troveranno un modo migliore per implementare le funzioni map, reduce e filter, basterà ricompilare il nostro codice per beneficiarne.

Vediamo adesso degli esempio in cui un classico ciclo FOR può essere espresso sfruttando il paradigma della Functional Programming.

Scenario 1: Estrarre una property da un Model Value

Abbiamo la seguente struct per rappresentare il nostro model

Inoltre abbiamo il seguente array.

Ora vogliamo creare un nuovo array contenente la lista di tutti i nomi presenti in persons.

Conoscendo bene il costrutto FOR scriveremmo qualcosa di questo tipo

Vediamo ora come possiamo eliminare il ciclo scrivendo codice funzionale.

Ora names contiene esattamente gli stessi dati di quando abbiamo usato il ciclo FOR. Ma abbiamo evitato tutti i problemi generati dal ciclo for infatti:

  1. Il codice è thread safe
  2. names è definito come una costante quindi non siamo stati costretti a ricorrere a valori mutabili
  3. il codice è estremamente più essenziale e leggibile

Scenario 2: Filtrare un array

Spesso usiamo il ciclo for per filtrare un array, o meglio per popolare un nuovo array contenenti solo quegli elementi dell’array sorgente che soddisfano una certa condizione.

Qui di seguito vediamo un ciclo FOR che aggiunge a personsWithBirthYear solo gli elementi di persons che hanno la proprietà birthYear popolata.

Vediamo ora come eliminare il ciclo FOR.

Ancora una volta abbiamo ottenuto lo stesso risultato scrivendo codice più essenziale, sicuro e performante.

Scenario 3: Costruire un nuovo valore

Vogliamo ora calcolare l’età media di tutte le persone in persons per le quali abbiamo una anno di nascita.

Un bel po’ di codice! Abbiamo 2 variabili (sumAges e numAges) che rischiano di essere modificate da un secondo thread e una logica imperativa dentro il blocco del FOR a rischio bug.

Vediamo cosa possiamo fare applicando la Functional Programmi e gettando via il ciclo FOR.

Con la prima riga di codice stiamo creando un array contenente tutte le date di nascita escludendo i valori nulli.

La seconda riga accumula la differenza tra 2016 e anno di nascita per ogni valore di birthYears e infine divide il risultato per il numero delle date di nascita.

Conclusione

L’idea di evitare i cicli FOR (e le variabili!) può sembrare estrema. Tuttavia con Swift e altri linguaggi di programmazione influenzati dalla Functional Programming è davvero possibile e garantisco che ne vale la pena. Dopo una fase iniziale di adattamento, riuscirete a scrivere codice di qualità superiore, sia da un punto di vista umano (leggibilità) che da quello del compilatore (sicurezza, performance).

Luca Angeletti

Trainer • Developer • Writer

Lascia un commento

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