Perché x < y < z
non è comunemente disponibile nei linguaggi di programmazione?
In questa risposta lo concludo
- sebbene questo costrutto sia banale da implementare nella grammatica di una lingua e crei valore per gli utenti della lingua,
- i motivi principali per cui ciò 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
- sconvolgere gli utenti con modifiche potenzialmente violenti
- per passare all'attuazione della funzione (es. pigrizia).
introduzione
Posso parlare dal punto di vista di un pitonista su questa domanda. Sono un utente di una lingua con questa funzione e mi piace studiare i dettagli di implementazione della lingua. Oltre a ciò, ho una certa familiarità con il processo di modifica di linguaggi come C e C ++ (lo standard ISO è governato da un comitato e aggiornato per anno) e ho visto sia Ruby che Python implementare le ultime modifiche.
Documentazione e implementazione di Python
Dalla documentazione / grammatica, vediamo che possiamo unire 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:
I confronti possono essere concatenati in modo arbitrario, ad es. X <y <= z è equivalente a x <y e y <= z, tranne per il fatto che y viene valutato solo una volta (ma in entrambi i casi z non viene valutato affatto quando viene trovato x <y essere falso).
Equivalenza logica
Così
result = (x < y <= z)
è logicamente equivalente in termini di valutazione di x
, y
e z
, con l'eccezione che y
viene valutata per 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 per il beneficio di quelle provenienti da altre lingue e il codice sopra è Python abbastanza legale.)
Ispezione dell'albero di sintassi 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 è davvero 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 accetta la prima espressione, un iterabile di confronti specifici e un iterabile di nodi di espressione da valutare se necessario. Semplice.
Conclusione su Python
Personalmente trovo che la semantica della gamma sia piuttosto 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).
Si noti che il codice viene letto molto più di quanto sia scritto. I cambiamenti che migliorano la leggibilità del codice dovrebbero essere abbracciati, non scontati sollevando spettri generici di Paura, Incertezza e Dubbio .
Quindi perché x <y <z non è comunemente disponibile nei linguaggi di programmazione?
Penso che ci sia una confluenza di ragioni incentrate sull'importanza relativa della caratteristica e sul relativo momento / inerzia del cambiamento consentito dai governatori delle lingue.
Domande simili possono essere poste su altre funzionalità linguistiche più importanti
Perché l'ereditarietà multipla non è disponibile in Java o C #? Non c'è una buona risposta qui a nessuna delle due domande . Forse gli sviluppatori erano troppo pigri, come sostiene Bob Martin, e le ragioni fornite sono semplicemente delle scuse. E l'ereditarietà multipla è un argomento piuttosto importante nell'informatica. È certamente più importante del concatenamento dell'operatore.
Esistono soluzioni semplici
Il concatenamento dell'operatore di confronto è elegante, ma non altrettanto importante dell'eredità multipla. E proprio come Java e C # hanno interfacce come soluzione alternativa, così fa ogni linguaggio per confronti multipli: è sufficiente concatenare i confronti con "e" s booleani, che funzionano abbastanza facilmente.
La maggior parte delle lingue sono governate dal comitato
La maggior parte delle lingue si sta evolvendo per comitato (piuttosto che avere un sensibile dittatore benevolo per la vita come ha fatto Python). E suppongo che questo problema non abbia visto abbastanza supporto per farcela dai suoi rispettivi comitati.
Le lingue che non offrono questa funzione possono cambiare?
Se una lingua lo consente x < y < z
senza la semantica matematica prevista, questo cambierebbe radicalmente. Se non lo consentisse in primo luogo, sarebbe quasi banale aggiungere.
Rottura dei cambiamenti
Per quanto riguarda le lingue con i cambiamenti di rotta: aggiorniamo le lingue con i cambiamenti del comportamento di rottura - ma gli utenti tendono a non apprezzare questo, in particolare gli utenti di funzionalità che potrebbero essere interrotte. Se un utente fa affidamento sul precedente comportamento di x < y < z
, probabilmente protesterebbe ad alta voce. E poiché la maggior parte delle lingue sono governate da una commissione, dubito che otterremmo molta volontà politica per sostenere un simile cambiamento.