Perché x < y < z
non è comunemente disponibile nei linguaggi di programmazione?
In questa risposta concludo che
- anche se questo costrutto è banale da implementare nella grammatica di una lingua e crea valore per gli utenti della lingua,
- i motivi principali per cui questo non esiste nella maggior parte delle lingue è dovuto alla sua importanza rispetto ad altre caratteristiche e alla riluttanza degli organi di governo delle lingue a
- sconvolge gli utenti con modifiche potenzialmente violente
- per spostarsi per implementare la funzione (es .: pigrizia).
Introduzione
Posso parlare dalla prospettiva di un pitista su questa domanda. Sono un utente di una lingua con questa funzione e mi piace studiare i dettagli di implementazione della lingua. Oltre a questo, ho una certa familiarità con il processo di modifica di linguaggi come C e C ++ (lo standard ISO è governato da comitato e versione per anno.) E ho visto sia Ruby che Python implementare i cambiamenti di rottura.
Documentazione e implementazione di Python
Dalla documentazione / grammatica, vediamo che possiamo concatenare qualsiasi numero di espressioni con operatori di confronto:
comparison ::= or_expr ( comp_operator or_expr )*
comp_operator ::= "<" | ">" | "==" | ">=" | "<=" | "!="
| "is" ["not"] | ["not"] "in"
e la documentazione afferma inoltre:
Comparisons can be chained arbitrarily, e.g., x < y <= z is equivalent to x < y and y <= z, except that y is evaluated only once (but in both cases z is not evaluated at all when x < y is found to be false).
Equivalenza logica
Quindi
result = (x < y <= z)
è logicamente equivalente in termini di valutazione di x
, y
e z
, con l'eccezione che y
viene valutata due volte:
x_lessthan_y = (x < y)
if x_lessthan_y: # z is evaluated contingent on x < y being True
y_lessthan_z = (y <= z)
result = y_lessthan_z
else:
result = x_lessthan_y
Ancora una volta, la differenza è che y viene valutato solo una volta con (x < y <= z)
.
(Nota, le parentesi sono completamente inutili e ridondanti, ma le ho usate a beneficio di quelle provenienti da altre lingue, e il codice sopra è un Python piuttosto legale.)
Ispezione dell'albero sintattico astratto analizzato
Possiamo esaminare come Python analizza gli operatori di confronto concatenati:
>>> import ast
>>> node_obj = ast.parse('"foo" < "bar" <= "baz"')
>>> ast.dump(node_obj)
"Module(body=[Expr(value=Compare(left=Str(s='foo'), ops=[Lt(), LtE()],
comparators=[Str(s='bar'), Str(s='baz')]))])"
Quindi possiamo vedere che questo non è difficile da analizzare per Python o qualsiasi altra lingua.
>>> ast.dump(node_obj, annotate_fields=False)
"Module([Expr(Compare(Str('foo'), [Lt(), LtE()], [Str('bar'), Str('baz')]))])"
>>> ast.dump(ast.parse("'foo' < 'bar' <= 'baz' >= 'quux'"), annotate_fields=False)
"Module([Expr(Compare(Str('foo'), [Lt(), LtE(), GtE()], [Str('bar'), Str('baz'), Str('quux')]))])"
E contrariamente alla risposta attualmente accettata, l'operazione ternaria è un'operazione di confronto generica, che prende la prima espressione, un iterabile di confronti specifici e un iterabile di nodi di espressione per valutare se necessario. Semplice.
Conclusione su Python
Personalmente ritengo che la semantica della gamma sia abbastanza elegante, e la maggior parte dei professionisti di Python che conosco incoraggerebbero l'uso della funzione, invece di considerarla dannosa - la semantica è chiaramente indicata nella documentazione ben nota (come notato sopra ).
Nota che il codice viene letto molto più di quanto non sia scritto. Le modifiche che migliorano la leggibilità del codice dovrebbero essere accolte, non scontate aumentando gli spettri generici di Paura, incertezza e dubbio .
Allora perché x < y < z non è comunemente disponibile nei linguaggi di programmazione?
Penso che ci sia una confluenza di ragioni che centrano l'importanza relativa della caratteristica e il relativo momento / inerzia del cambiamento consentito dai governatori delle lingue.
Domande simili possono essere poste su altre funzioni linguistiche più importanti
Perché l'ereditarietà multipla non è disponibile in Java o C #? Qui non c'è una buona risposta a nessuna domanda . Forse gli sviluppatori erano troppo pigri, come sostiene Bob Martin, e le ragioni fornite sono solo scuse. E l'ereditarietà multipla è un argomento piuttosto importante nell'informatica. È certamente più importante della concatenazione dell'operatore.
Esistono soluzioni alternative
Il concatenamento degli operatori di confronto è elegante, ma non altrettanto importante quanto l'ereditarietà multipla. E proprio come Java e C # hanno interfacce come soluzione alternativa, così come ogni linguaggio per confronti multipli: si concatenano semplicemente i confronti con boolean "e" s, che funziona abbastanza facilmente.
La maggior parte delle lingue sono governate da un comitato
La maggior parte delle lingue si evolvono in commissione (piuttosto che avere un Dictator Benevolente per la vita come Python ha). E ipotizzo che questo problema non abbia visto abbastanza supporto per farlo uscire dalle rispettive commissioni.
Le lingue che non offrono questa funzione possono cambiare?
Se una lingua consente x < y < z
senza la semantica matematica prevista, questo sarebbe un cambio di rottura. Se non lo permettesse in primo luogo, sarebbe quasi banale da aggiungere.
Ultime modifiche
Per quanto riguarda le lingue con cambiamenti radicali: aggiorniamo le lingue con i cambiamenti del comportamento di rottura - ma gli utenti tendono a non gradire questo, specialmente gli utenti di funzionalità che potrebbero essere violate. Se un utente fa affidamento sul precedente comportamento di x < y < z
, probabilmente protesterebbe a voce alta. E poiché la maggior parte delle lingue sono governate da un comitato, dubito che avremmo molta volontà politica per sostenere un tale cambiamento.