¿Por qué x < y < z
no está comúnmente disponible en lenguajes de programación?
En esta respuesta concluyo que
- aunque esta construcción es trivial para implementar en la gramática de un lenguaje y crea valor para los usuarios del lenguaje,
- Las razones principales por las que esto no existe en la mayoría de los idiomas se deben a su importancia en relación con otras características y la falta de voluntad de los órganos rectores de los idiomas para
- usuarios molestos con cambios potencialmente importantes
- moverse para implementar la función (es decir, pereza).
Introducción
Puedo hablar desde la perspectiva de un pitonista sobre esta cuestión. Soy usuario de un idioma con esta función y me gusta estudiar los detalles de implementación del idioma. Más allá de esto, estoy algo familiarizado con el proceso de cambiar lenguajes como C y C ++ (el estándar ISO se rige por comité y versionado por año) y he visto a Ruby y Python implementar cambios importantes.
Documentación e implementación de Python
De los documentos / gramática, vemos que podemos encadenar cualquier número de expresiones con operadores de comparación:
comparison ::= or_expr ( comp_operator or_expr )*
comp_operator ::= "<" | ">" | "==" | ">=" | "<=" | "!="
| "is" ["not"] | ["not"] "in"
y la documentación además establece:
Las comparaciones se pueden encadenar arbitrariamente, por ejemplo, x <y <= z es equivalente a x <y e y <= z, excepto que y se evalúa solo una vez (pero en ambos casos z no se evalúa en absoluto cuando se encuentra x <y ser falso)
Equivalencia lógica
Asi que
result = (x < y <= z)
es lógicamente equivalente en términos de evaluación de x
, y
y z
, con la excepción de que y
se evalúa dos veces:
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
Nuevamente, la diferencia es que y se evalúa solo una vez con (x < y <= z)
.
(Tenga en cuenta que los paréntesis son completamente innecesarios y redundantes, pero los usé en beneficio de los que provienen de otros idiomas, y el código anterior es Python bastante legal).
Inspección del árbol de sintaxis abstracta analizado
Podemos inspeccionar cómo Python analiza los operadores de comparación encadenados:
>>> 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')]))])"
Entonces podemos ver que esto realmente no es difícil de analizar para Python o cualquier otro lenguaje.
>>> 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')]))])"
Y, contrariamente a la respuesta actualmente aceptada, la operación ternaria es una operación de comparación genérica, que toma la primera expresión, un iterable de comparaciones específicas y un iterable de nodos de expresión para evaluar según sea necesario. Simple.
Conclusión sobre Python
Personalmente, considero que la semántica de rango es bastante elegante, y la mayoría de los profesionales de Python que conozco alentarían el uso de la función, en lugar de considerarla dañina: la semántica está claramente establecida en la documentación de buena reputación (como se señaló anteriormente).
Tenga en cuenta que el código se lee mucho más de lo que se escribe. Los cambios que mejoran la legibilidad del código deben ser aceptados, no descartados mediante la aparición de espectros genéricos de miedo, incertidumbre y duda .
Entonces, ¿por qué x <y <z no está comúnmente disponible en lenguajes de programación?
Creo que hay una confluencia de razones que se centran en la importancia relativa de la característica y el momento / inercia relativa de cambio permitidos por los gobernadores de los idiomas.
Se pueden hacer preguntas similares sobre otras características del lenguaje más importantes
¿Por qué no hay herencia múltiple disponible en Java o C #? No hay una buena respuesta aquí para ninguna de las preguntas . Quizás los desarrolladores fueron demasiado vagos, como alega Bob Martin, y las razones dadas son meras excusas. Y la herencia múltiple es un tema bastante importante en informática. Ciertamente es más importante que el encadenamiento del operador.
Existen soluciones simples
El encadenamiento de operadores de comparación es elegante, pero de ninguna manera es tan importante como la herencia múltiple. Y al igual que Java y C # tienen interfaces como solución alternativa, también lo hace cada lenguaje para comparaciones múltiples: simplemente encadena las comparaciones con "y" s booleanos, que funcionan con bastante facilidad.
La mayoría de los idiomas están regidos por un comité.
La mayoría de los idiomas están evolucionando por comité (en lugar de tener un dictador benévolo para la vida sensible como Python). Y especulo que este tema simplemente no ha visto suficiente apoyo para salir de sus respectivos comités.
¿Pueden cambiar los idiomas que no ofrecen esta función?
Si un lenguaje lo permite x < y < z
sin la semántica matemática esperada, este sería un cambio radical. Si no lo permitía en primer lugar, sería casi trivial agregarlo.
Rompiendo cambios
En cuanto a los idiomas con romper cambios: hacemos idiomas de actualización a la rotura de los cambios de comportamiento - pero los usuarios tienden a no como este, especialmente los usuarios de características que pueden ser rotas. Si un usuario se basa en el comportamiento anterior de x < y < z
, lo más probable es fuertemente protestar. Y puesto que la mayoría de los idiomas se rigen por el comité, no creo que se pueden conseguir mucha voluntad política para apoyar un cambio de este tipo.