Molte lingue scelgono il percorso per rendere l'assegnazione un'istruzione anziché un'espressione, incluso Python:
foo = 42 # works
if foo = 42: print "hi" # dies
bar(foo = 42) # keyword arg
e Golang:
var foo int
foo = 42 # works
if foo = 42 { fmt.Printn("hi") } # dies
Altre lingue non hanno assegnazioni, ma piuttosto associazioni con ambito, ad esempio OCaml:
let foo = 42 in
if foo = 42 then
print_string "hi"
Tuttavia, let
è un'espressione stessa.
Il vantaggio di consentire l'assegnazione è che possiamo verificare direttamente il valore di ritorno di una funzione all'interno del condizionale, ad esempio in questo frammento di Perl:
if (my $result = some_computation()) {
say "We succeeded, and the result is $result";
}
else {
warn "Failed with $result";
}
Perl ambisce inoltre alla dichiarazione solo a quella condizionale, il che la rende molto utile. Avvertirà anche se si assegna all'interno di un condizionale senza dichiarare una nuova variabile lì - if ($foo = $bar)
avvertirà, if (my $foo = $bar)
non lo farà.
Effettuare l'assegnazione in un'altra istruzione è generalmente sufficiente, ma può causare problemi di scoping:
my $result = some_computation()
if ($result) {
say "We succeeded, and the result is $result";
}
else {
warn "Failed with $result";
}
# $result is still visible here - eek!
Golang si basa fortemente sui valori di ritorno per il controllo degli errori. Consente quindi a un condizionale di prendere una dichiarazione di inizializzazione:
if result, err := some_computation(); err != nil {
fmt.Printf("Failed with %d", result)
}
fmt.Printf("We succeeded, and the result is %d\n", result)
Altre lingue usano un sistema di tipi per non consentire espressioni non booleane all'interno di un condizionale:
int foo;
if (foo = bar()) // Java does not like this
Naturalmente ciò fallisce quando si utilizza una funzione che restituisce un valore booleano.
Ora abbiamo visto diversi meccanismi per difendersi da incarichi accidentali:
- Non consentire l'assegnazione come espressione
- Utilizzare il controllo del tipo statico
- L'assegnazione non esiste, abbiamo solo
let
attacchi
- Consenti una dichiarazione di inizializzazione, non consentire diversamente l'assegnazione
- Non consentire l'assegnazione all'interno di un condizionale senza dichiarazione
Li ho classificati in ordine di preferenza crescente - i compiti all'interno delle espressioni possono essere utili (ed è semplice aggirare i problemi di Python avendo una sintassi di dichiarazione esplicita e una diversa sintassi dell'argomento denominato). Ma va bene impedirle, poiché ci sono molte altre opzioni per lo stesso effetto.
Il codice privo di bug è più importante del codice conciso.