Valutazione a corto circuito
La valutazione a corto circuito, valutazione minima o valutazione di McCarthy è un meccanismo relativo agli operatori booleani binari per cui il secondo operando viene valutato unicamente se il valore del primo operando non è sufficiente da solo a determinare il risultato dell'espressione: quando il primo argomento dell'operatore logico AND è falso , il valore dell'intera espressione dovrà essere necessariamente falso ; e quando il primo argomento dell'operatore logico OR è vero , il valore dell'intera espressione dovrà essere necessariamente vero . In alcuni linguaggi di programmazione (Lisp), i normali operatori booleani sono cortocircuitati. In altri (Ada, Java), sono disponibili sia operatori cortocircuitati che non. Per alcuni operatori booleani, come Disgiunzione esclusiva (XOR), non è possibile cortocircuitare, perché entrambi gli operandi sono sempre richiesti per determinare il risultato.
La valutazione a corto circuito, prevista in numerosi linguaggi di programmazione, è usata sia per sveltire il calcolo del risultato delle espressioni, sia come forma compatta di un'istruzione condizionale qualora la valutazione del secondo operando produca degli effetti collaterali.
Supporto nei comuni linguaggi di programmazione
Operatori booleani nei vari linguaggi
Linguaggio |
Operatori eager |
Operatori di cortocircuito |
Tipo di risultato
|
Advanced Business Application Programming (ABAP)
|
nessuno
|
and , or
|
Booleano1
|
Ada
|
and , or
|
and then , or else
|
Booleano
|
ALGOL 68
|
and, &, ∧ ; or, ∨
|
andf , orf (entrambi definiti dall'utente)
|
Booleano
|
C, Objective-C
|
nessuno
|
&& , || , ? [1]
|
int (&& ,|| ), opnd-dipendente (? )
|
C++2
|
& , |
|
&& , || , ? [2]
|
Booleano (&& ,|| ), opnd-dipendente (? )
|
C#
|
& , |
|
&& , || , ? , ??
|
Booleano (&& ,|| ), opnd-dipendente (? , ?? )
|
ColdFusion Markup Language (CFML)
|
nessuno
|
AND , OR , && , ||
|
Booleano
|
D3
|
& , |
|
&& , || , ?
|
Booleano (&& ,|| ), opnd-dipendente (? )
|
Eiffel
|
and , or
|
and then , or else
|
Booleano
|
Erlang
|
and , or
|
andalso , orelse
|
Booleano
|
Fortran4
|
.and. , .or.
|
.and. , .or.
|
Booleano
|
Go, Haskell, OCaml
|
nessuno
|
&& , ||
|
Booleano
|
Java, MATLAB, R, Swift
|
& , |
|
&& , ||
|
Booleano
|
JavaScript, Julia
|
& , |
|
&& , ||
|
Ultimo valore
|
Lasso
|
nessuno
|
and , or , && , ||
|
Ultimo valore
|
Lisp, Lua, Scheme
|
nessuno
|
and , or
|
Ultimo valore
|
MUMPS (M)
|
& , !
|
nessuno
|
Numerico
|
Modula-2
|
nessuno
|
AND , OR
|
Booleano
|
Oberon
|
nessuno
|
& , OR
|
Booleano
|
OCaml
|
nessuno
|
&& , ||
|
Booleano
|
Pascal
|
and , or 5
|
and_then , or_else 6
|
Booleano
|
Perl, Ruby
|
& , |
|
&& , and , || , or
|
Ultimo valore
|
PHP
|
& , |
|
&& , and , || , or
|
Booleano
|
Python
|
& , |
|
and , or
|
Ultimo valore
|
Smalltalk
|
& , |
|
and: , or: 7
|
Booleano
|
Standard ML
|
Sconosciuto
|
andalso , orelse
|
Booleano
|
Visual Basic .NET
|
And , Or
|
AndAlso , OrElse
|
Booleano
|
VBScript, Visual Basic, Visual Basic for Applications (VBA)
|
And , Or
|
Case di selezione 8
|
Numerico
|
Wolfram Language
|
And @@ {...} , Or @@ {...}
|
And , Or , && , ||
|
Booleano
|
1 ABAP non ha tipi booleani differenti.
2 In caso di overload, gli operatori && e || sono eager e possono ritornare qualunque tipo.
3 Questo vale solo per le espressioni valutate a runtime, static if e static assert . Le espressioni negli inizializzatori static o nelle costanti manifest usano la valutazione eager.
4 Gli operatori Fortran non sono né cortocircuitati né eager: le specifiche del linguaggio permettono al compilatore di selezionare il metodo per l'ottimizzazione.
5 Il Pascal esteso (ISO/IEC 10206:1990) permette, ma non richiede, il cortocircuito.
6 Il Pascal esteso (ISO/IEC 10206:1990 supporta and_then e or_else .[3]
7 Smalltalk usa la semantica del cortocircuito solo se l'argomento di and: è un blocco (es.: false and: [Transcript show: 'Non apparirò!'] ).
8 I linguaggi BASIC che hanno supportato le istruzioni CASE lo hanno fatto usando un sistema di valutazione condizionale, invece che tabelle di salto limitate ad etichette (label) fisse.
Usi comuni
In uno script di shell:
test -d /tmp/foo || mkdir /tmp/foo
In questo caso il comando mkdir /tmp/foo viene eseguito unicamente se il risultato del primo comando (che verifica l'esistenza della directory /tmp/foo) è falso, per via della valutazione a corto circuito dell'operatore OR (indicato come || nello script). Rappresenta una forma compatta di
if ! test -d /tmp/foo; then mkdir /tmp/foo; fi
Evitare effetti indesirati del secondo argomento
Nel linguaggio C:
if (denom != 0 && num / denom)
{
... // assicura che l'espressione num / denom non risulti mai in un errore a causa del denominatore nullo (denom==0)
}
Si consideri il seguente esempio:
int a = 0;
if (a != 0 && myfunc(b))
{
do_something();
}
In questo esempio, la valutazione a cortocircuito garantisce che myfunc(b) non venga mai chiamata. Questo perché l'espressione a != 0 risulta in false. Questa caratteristica permette due utili costrutti di programmazione. Come prima cosa, la prima sotto-espressione può essere usata per controllare se è necessario un ulteriore calcolo e se il risultato è false si possono eliminare i calcoli non necessari del secondo argomento. Secondariamente, permette un costrutto dove la prima espressione garantisce una condizione senza la quale la seconda espressione potrebbe causare un errore di runtime. Essi sono entrambi illustrati nei seguenti codici C dove la valutazione minima evita sia la dereferenziazione con puntatore nullo sia un eccesso di prelievi in memoria:
bool is_first_char_valid_alpha_unsafe(const char *p)
{
return isalpha(p[0]); // SEGFAULT altamente probabile con p == NULL
}
bool is_first_char_valid_alpha(const char *p)
{
return p != NULL && isalpha(p[0]); // a) nessuna necessità di eseguire isalpha() con p == NULL, b) nessun rischio di SEGFAULT
}
Note
Voci correlate
|