Short-circuit boolean evaluation: mai dare niente per scontato
di Francesco Sblendorio
Leggete questo segmento di codice java:
Ciò che fa è molto semplice: controlla se la collezione list è non nulla e con almeno un elemento e in tal caso esegue un metodo chiamato doSomething().
La condizione booleana è un AND di due espressioni, e l’ordine in cui vengono calcolate non è affatto indifferente: viene valutata per prima list != null, e se questa risulta già essere FALSE, l’intera condizione viene fatta valere FALSE senza nemmeno valutare list.size()>0, anche perché in tal caso list sarebbe uguale a null, quindi qualunque chiamata a metodo su list finirebbe in una NullPointerException.
Un discorso analogo viene fatto per l’operazione di OR: se il primo operando risulta già essere TRUE, l’espressione viene fatta valere TRUE senza valutare il secondo operando.
Questa caratteristica (la valutazione parziale delle espressioni booleane) si chiama Short-circuit evalutation ed è una differenza fondamentale tra un’operazione di AND in Java e l’operazione di AND nel mondo matematico. Nel mondo della matematica l’ordine di valutazione è totalmente indifferente in quanto l’operatore di AND è commutativo.
Nel mondo “reale” dell’informatica questo trucchetto viene invece utilizzato non tanto per aumentare le performance quanto per scrivere condizioni più compatte: nell’esempio precedente, senza la short-circuit evaluation si solleverebbe una NullPointerException se list fosse null, e bisognerebbe invece riscrivere il codice in questo modo:
(evitando cioè “a mano” di eseguire il metodo .size() su un oggetto null).
Questo tipo di controlli torna utile in tutta una serie di occasioni:
- Check dei boundary di un array o di una stringa
- Evitare divisioni per zero
- Evitare di utilizzare valori nulli (come in questo caso)
Tutto ciò oggigiorno viene dato per scontato, ma qui siamo su RetroAcademy, quindi siamo gente a cui piace programmare anche su architetture obsolete e dimenticate da anni in virtù della nostra vena di “archeologi informatici”. I vecchi linguaggi (e relativi compilatori) supportano la short-circuit evaluation?
La risposta è: “dipende”. Alcuni linguaggi, per esempio Modula-2, la supportano by design. Altri linguaggi hanno subìto nel tempo diverse revisioni e standardizzazioni (è il caso del C): in questi casi dipende dal tipo di standard adottato dal compilatore. In altri casi ancora le specifiche sono talmente lasche (è il caso del BASIC) che non vi è dubbio che ciò dipenda dal compilatore/interprete utilizzato.
In questo articolo viene presentato un caso di studio costituito da un semplice test:
– Dati due interi A e B, stampare il valore di A/B se e solo se A/B è maggiore di 1. Altrimenti segnalare errore.
Questo test è stato implementato in 5 linguaggi diversi supponendo che valga la short-circuit evaluation. I test sono stati lanciati e si è visto in questo modo se la short-circuit evaluation sia stata utilizzata o meno.
Il sistema operativo di riferimento utilizzato è stato CP/M-80 (tranne ovviamente nel caso di Java) e i linguaggi/compilatori testati sono stati:
Compilatore | S.O. | Esito | Revisione delle condizione |
Java 7 | JVM | OK: Short-circuit evaluation | – |
Turbo Modula-2 | CP/M-80 | OK: Short-circuit evaluation | – |
Turbo Pascal 3.01A | CP/M-80 | KO: Crash del programma | |
Hi-Tech C 3.09 | CP/M-80 | KO: Crash del sistema operativo | |
MBASIC-80 5.21 | CP/M-80 | KO: Comportamento imprevisto | IF B<>0 THEN IF A/B>1 THEN |
Di seguito i segmenti di codice nei vari linguaggi:
Java |
Turbo Modula-2 |
Turbo Pascal 3.01A |
Hi-Tech C 3.09 |
MBASIC-80 5.21 |
In sintesi: attenzione! Ciò che potrebbe a una prima occhiata sembrare corretto in realtà potrebbe non esserlo, specie se si tratta di un’abitudine ormai data per scontata ma che è solo il risultato dell’evoluzione che i linguaggi hanno subìto negli anni.
Per approfondimenti:
– Pagina di Wikipedia sulla short-circuit evaluation: parla anche dei possibili “side-effect” non desiderati
Commenti
Posta un commento