¿Por qué la mayoría de los idiomas convencionales no admiten la sintaxis "x <y <z" para las comparaciones booleanas de 3 vías?

34

Si quiero comparar dos números (u otras entidades bien ordenadas), lo haría con x < y. Si quiero comparar tres de ellos, el estudiante de álgebra de secundaria me sugerirá intentarlo x < y < z. El programador en mí responderá con "no, eso no es válido, tienes que hacerlo x < y && y < z".

La mayoría de los lenguajes que he encontrado no parecen admitir esta sintaxis, lo cual es extraño dado lo común que es en matemáticas. Python es una notable excepción. JavaScript parece una excepción, pero en realidad es solo un desafortunado subproducto de la precedencia del operador y las conversiones implícitas; en node.js, 1 < 3 < 2evalúa a true, porque es realmente (1 < 3) < 2 === true < 2 === 1 < 2.

Entonces, mi pregunta es esta: ¿Por qué x < y < zno está comúnmente disponible en lenguajes de programación, con la semántica esperada?

JesseTG
fuente
1
Aquí está el archivo de gramática, que pegan fácilmente en la documentación de Python. No creo que sea tan difícil: docs.python.org/reference/grammar.html
Aaron Hall
No conozco otros idiomas tan bien como Python, pero puedo hablar de la simplicidad de la interpretación que Python hace de él. Quizás debería responder. Pero no estoy de acuerdo con la conclusión de gnasher729 sobre que está haciendo daño.
Aaron Hall
@ErikEidt: la demanda es poder escribir expresiones matemáticas de la forma en que nos enseñaron en la escuela secundaria (o antes). Todos los que tienen una inclinación matemática saben lo que significa $ a <b <c <d $. El hecho de que exista una función no significa que deba usarla. Aquellos a quienes no les gusta siempre pueden hacer una regla personal o de proyecto que prohíba su uso.
David Hammen
2
Creo que todo se reduce a que es mejor que el equipo de C # (como ejemplo) explore LINQ y en el futuro tal vez registre tipos y coincidencia de patrones que agregar un poco de azúcar sintáctico que ahorraría a las personas 4 pulsaciones de teclas y no realmente agregue cualquier expresividad (también puede escribir métodos auxiliares como static bool IsInRange<T>(this T candidate, T lower, T upper) where T : IComparable<T>si realmente le molestara ver &&s)
sara
1
SQL es bastante "mainstream" y puedes escribir "x entre 1 y 10"
JoelFan

Respuestas:

30

Estos son operadores binarios, que cuando se encadenan, normalmente y naturalmente producen un árbol de sintaxis abstracta como:

árbol de sintaxis abstracta normal para operadores binarios

Cuando se evalúa (lo que haces desde las hojas hacia arriba), esto produce un resultado booleano x < y, luego obtienes un error de tipo al intentar hacerlo boolean < z. Para x < y < zque funcione como lo discutió, debe crear un caso especial en el compilador para producir un árbol de sintaxis como:

árbol de sintaxis de casos especiales

No es que no sea posible hacer esto. Obviamente lo es, pero agrega cierta complejidad al analizador para un caso que realmente no aparece con tanta frecuencia. Básicamente, está creando un símbolo que a veces actúa como un operador binario y, a veces, actúa efectivamente como un operador ternario, con todas las implicaciones del manejo de errores y todo lo que ello conlleva. Eso agrega mucho espacio para que las cosas salgan mal que los diseñadores de idiomas preferirían evitar si fuera posible.

Karl Bielefeldt
fuente
1
"entonces aparece un error de tipo al intentar hacer boolean <z", no si el compilador permite el encadenamiento evaluando y en el lugar para la comparación z. "Eso agrega mucho espacio para que las cosas salgan mal que los diseñadores de idiomas preferirían evitar si es posible". En realidad, Python no tiene problemas para hacer esto, y la lógica para analizar se limita a una sola función: hg.python.org/cpython/file/tip/Python/ast.c#l1122 : no hay mucho espacio para las cosas. incorrecto. "a veces actúa como un operador binario y a veces actúa efectivamente como un operador trinario", en Python, toda la cadena de comparación es ternaria.
Aaron Hall
2
Nunca dije que no era factible, solo trabajo extra con complejidad extra. Otros idiomas no tienen que escribir ningún código separado solo para manejar sus operadores de comparación. Lo obtienes gratis con otros operadores binarios. Solo tiene que especificar su precedencia.
Karl Bielefeldt
Sí, pero ... ¿ ya hay un operador ternario disponible en muchos idiomas?
JensG
1
@JensG La denotación de ternario significa que se necesitan 3 argumentos. En el contexto de su enlace, es un operador de condición ternaria. Aparentemente "trinario" en un término acuñado para un operador que parece tomar 2 pero en realidad toma 3. Mi principal problema con esta respuesta es que es principalmente FUD.
Aaron Hall
2
Soy uno de los votantes negativos en esta respuesta aceptada. (@JesseTG:. Por favor, inaceptables desde esta respuesta) Esta pregunta se confunde qué x<y<zmedios, o que es más importante, x<y<=z. Esta respuesta se interpreta x<y<zcomo un operador trinario. Así es exactamente cómo no debe interpretarse esta expresión matemática bien definida. x<y<zes en cambio la abreviatura de (x<y)&&(y<z). Las comparaciones individuales siguen siendo binarias.
David Hammen
37

¿Por qué x < y < zno 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, yy z, con la excepción de que yse 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 < zsin 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.

Aaron Hall
fuente
Sinceramente, me da ningún problema con la semántica proporcionados por los idiomas que las operaciones de comparación de cadena como `x <y <z` pero es trivial para un desarrollador para trazar mentalmente x < y < za (x < y) && (y < z). Recoger las liendres, el modelo mental para la comparación en cadena es de matemáticas general. La comparación clásica no las matemáticas en general es, pero la lógica booleana. x < yproduce una respuesta binaria {0}. y < zproduce una respuesta binaria {1}. {0} && {1}produce la respuesta descriptiva. La lógica se compone, no encadenado ingenuamente.
K. Alan Bates
Para comunicarme mejor, he precedido la respuesta con una sola oración que resume directamente todo el contenido. Es una oración larga, así que la dividí en balas.
Aaron Hall
2
La razón clave por la que pocos idiomas implementan esta característica es que antes de Guido, nadie lo pensaba. Los lenguajes que heredan de C no pueden hacer esto "correcto" (matemáticamente correcto) ahora principalmente porque los desarrolladores de C lo hicieron "incorrecto" (matemáticamente incorrecto) hace más de 40 años. Hay mucho código por ahí que depende de la naturaleza contraintuitiva de cómo interpretan esos idiomas x<y<z. Una vez, un idioma tiene la oportunidad de hacer algo como esto correctamente, y esa única oportunidad es al inicio del idioma.
David Hammen
1
@ K.AlanBates Haces 2 puntos: 1) el encadenamiento del operador es descuidado y 2) que el azúcar sintáctico no tiene valor. Al primero: he demostrado que el encadenamiento de operadores es 100% determinista, ¿no es así? ¿Quizás algunos programadores son demasiado vagos para expandir su capacidad de comprender el constructo? Para el segundo punto: ¿Me parece que estás discutiendo directamente contra la legibilidad? ¿No se considera que el azúcar sintáctico es algo bueno cuando mejora la legibilidad? Si es normal pensar de esta manera, ¿por qué un programador no querría comunicarse de esta manera? El código debe estar escrito para ser leído, ¿no?
Aaron Hall
2
I have watched both Ruby and Python implement breaking changes.Para aquellos que tienen curiosidad, aquí hay un cambio importante en C # 5.0 que involucra variables de ciclo y cierres: blogs.msdn.microsoft.com/ericlippert/2009/11/12/…
user2023861
13

Los lenguajes de computadora intentan definir las unidades más pequeñas posibles y le permiten combinarlas. La unidad más pequeña posible sería algo así como "x <y" que da un resultado booleano.

Puede solicitar un operador ternario. Un ejemplo sería x <y <z. Ahora, ¿qué combinaciones de operadores permitimos? Obviamente x> y> z o x> = y> = z o x> y> = z o tal vez x == y == z debería estar permitido. ¿Qué pasa con x <y> z? x! = y! = z? ¿Qué significa el último, x! = Y e y! = Z o que los tres son diferentes?

Ahora promociones de argumentos: en C o C ++, los argumentos serían promovidos a un tipo común. Entonces, ¿qué significa x <y <z de x es doble pero y y z son largas, largas int? ¿Los tres ascendieron al doble? ¿O y se toma como doble una vez y tanto tiempo como la otra vez? ¿Qué sucede si en C ++ uno o ambos operadores están sobrecargados?

Y por último, ¿permite algún número de operandos? ¿Como a <b> c <d> e <f> g?

Bueno, todo se vuelve muy complicado. Ahora, lo que no me importaría es que x <y <z produzca un error de sintaxis. Porque su utilidad es pequeña en comparación con el daño causado a los principiantes que no pueden entender qué hace realmente x <y <z.

gnasher729
fuente
44
En resumen, es solo una característica difícil de diseñar bien.
Jon Purdy
2
Esto no es realmente una razón para explicar por qué un lenguaje no conocido contiene esta característica. De hecho, es bastante fácil incluirlo en un idioma de una manera bien definida. Es solo una cuestión de verlo como una lista conectada por operadores de tipo similar en lugar de que cada operador sea binario. Lo mismo puede hacerse para sumas x + y + z, con la única diferencia de que eso no implica ninguna diferencia semántica. Por lo tanto, es que ningún idioma conocido se haya preocupado por hacerlo.
cmaster
1
Creo que en Python es una optimización, ( x < y < zequivalente a ((x < y) and (y < z))pero ysolo evaluada una vez ), lo que me imagino que los lenguajes compilados optimizan. "Debido a que su utilidad es pequeña en comparación con el daño causado a los principiantes que no pueden entender qué hace realmente x <y <z". Creo que es increíblemente útil. Probablemente va a -1 por eso ...
Aaron Hall
Si el objetivo de uno es diseñar un lenguaje que elimine todas las cosas que pueden ser confusas para los programadores más tontos, ese lenguaje ya existe: COBOL. Prefiero usar Python, yo mismo, donde uno puede escribir a < b > c < d > e < f > g, con el significado "obvio" (a < b) and (b > c) and (c < d) and (d > e) and (e < f) and (f > g). El hecho de que puedas escribir no significa que debas hacerlo. Eliminar tales monstruosidades es el ámbito de la revisión del código. Por otro lado, escribir 0 < x < 8en python tiene el obvio (sin comillas de miedo), lo que significa que x se encuentra entre 0 y 8, exclusivo.
David Hammen
@DavidHammen, irónicamente, COBOL sí permite un <b <c
JoelFan
10

En muchos lenguajes de programación, x < yes una expresión binaria que acepta dos operandos y se evalúa como un único resultado booleano. Por lo tanto, si encadena múltiples expresiones, true < zy false < zno tiene sentido, y si esas expresiones se evalúan con éxito, es probable que produzcan el resultado incorrecto.

Es mucho más fácil pensar x < yen una llamada de función que toma dos parámetros y produce un único resultado booleano. De hecho, así es como muchos idiomas lo implementan bajo el capó. Es composable, fácilmente compilable, y simplemente funciona.

El x < y < zescenario es mucho más complicado. Ahora el compilador, en efecto, tiene a la moda tres funciones: x < y, y < zy el resultado de esos dos valores anded juntos, todo ello dentro del contexto de una discutible gramática lenguaje ambiguo .

¿Por qué lo hicieron al revés? Porque es una gramática inequívoca, mucho más fácil de implementar y mucho más fácil de corregir.

Robert Harvey
fuente
2
Si está diseñando el lenguaje, tiene la oportunidad de hacerlo el resultado correcto .
JesseTG
2
Por supuesto que responde la pregunta. Si la pregunta es realmente por qué , la respuesta es "porque eso es lo que eligieron los diseñadores de idiomas". Si puede encontrar una mejor respuesta que esa, hágalo. Tenga en cuenta que Gnasher esencialmente dijo exactamente lo mismo en el primer párrafo de su respuesta .
Robert Harvey
3
De nuevo, estás dividiendo pelos. Los programadores tienden a hacer eso. "¿Quieres sacar la basura?" "No." "¿Sacarás la basura?" "Sí."
Robert Harvey
2
También impugno el último párrafo. Python admite comparaciones de cadenas, y su analizador es LL (1). Tampoco es necesariamente difícil definir e implementar la semántica: Python solo dice que e1 op1 e2 op2 e3 op3 ...es equivalente a e1 op e2 and e2 op2 e3 and ...excepto que cada expresión solo se evalúa una vez. (Por cierto, esta simple regla tiene el efecto secundario confuso de que declaraciones como a == b is Trueya no tienen el efecto deseado).
2
@RobertHarvey re:answerAquí fue donde mi mente fue inmediatamente para mi comentario sobre la pregunta principal. No considero soporte para x < y < zagregar ningún valor específico a la semántica del lenguaje. (x < y) && (y < z)tiene un soporte más amplio, es más explícito, más expresivo, se digiere más fácilmente en sus componentes, es más composable, más lógico, se refactoriza más fácilmente.
K. Alan Bates
6

La mayoría de los lenguajes principales están (al menos parcialmente) orientados a objetos. Fundamentalmente, el principio subyacente de OO es que los objetos envían mensajes a otros objetos (o a ellos mismos), y el receptor de ese mensaje tiene control total sobre cómo responder a ese mensaje.

Ahora, veamos cómo implementaríamos algo como

a < b < c

Podríamos evaluarlo estrictamente de izquierda a derecha (asociativo a la izquierda):

a.__lt__(b).__lt__(c)

Pero ahora invocamos __lt__el resultado de a.__lt__(b), que es a Boolean. Eso no tiene sentido.

Probemos asociativo correcto:

a.__lt__(b.__lt__(c))

No, eso tampoco tiene sentido. Ahora tenemos a < (something that's a Boolean).

Bien, ¿qué hay de tratarlo como azúcar sintáctico? Hagamos que una cadena de n <comparaciones envíe un mensaje n-1-ary. Esto podría significar que enviamos el mensaje __lt__a a, pasando by ccomo argumentos:

a.__lt__(b, c)

Bien, eso funciona, pero aquí hay una asimetría extraña: adecide si es menor que b. Pero bno llega a decidir si es menor que c, sino que esa decisión también es tomada por a.

¿Qué hay de interpretarlo como un mensaje n-ary enviado a this?

this.__lt__(a, b, c)

¡Finalmente! Esto puede funcionar Significa, sin embargo, que el orden de los objetos ya no es una propiedad del objeto (por ejemplo, si aes menor que bni una propiedad ani una de b), sino una propiedad del contexto (es decir this).

Desde un punto de vista convencional que parece extraño. Sin embargo, por ejemplo, en Haskell, eso es normal. Puede haber múltiples implementaciones diferentes de la Ordclase de tipos, por ejemplo, y si es o no amenor que b, depende de qué instancia de tipo de clase esté dentro del alcance.

Pero, en realidad, no es que raro en absoluto! Tanto Java ( Comparator) como .NET ( IComparer) tienen interfaces que le permiten inyectar su propia relación de orden en, por ejemplo, algoritmos de clasificación. Por lo tanto, reconocen plenamente que un pedido no es algo que se fija a un tipo, sino que depende del contexto.

Hasta donde yo sé, actualmente no hay idiomas que realicen dicha traducción. Sin embargo, existe una precedencia: tanto Ioke como Seph tienen lo que su diseñador llama "operadores trinarios": operadores que son sintácticamente binarios, pero semánticamente ternarios. En particular,

a = b

se no se interpreta como que envía el mensaje =a apasar bcomo argumento, sino más bien como enviar el mensaje =a la "corriente de tierra" (un concepto similar pero no idéntica a this) pasar ay bcomo argumentos. Entonces, a = bse interpreta como

=(a, b)

y no

a =(b)

Esto podría generalizarse fácilmente a los operadores n-arios.

Tenga en cuenta que esto es realmente peculiar de los lenguajes OO. En OO, siempre tenemos un único objeto que es en última instancia responsable de interpretar el envío de un mensaje, y como hemos visto, no es inmediatamente obvio para algo como a < b < cqué objeto debería ser.

Sin embargo, esto no se aplica a los lenguajes de procedimiento o funcionales. Por ejemplo, en Scheme , Common Lisp y Clojure , el< función es n-aria y se puede llamar con un número arbitrario de argumentos.

En particular, <hace no media "menor que", en lugar de estas funciones se interpretan de forma ligeramente diferente:

(<  a b c d) ; the sequence a, b, c, d is monotonically increasing
(>  a b c d) ; the sequence a, b, c, d is monotonically decreasing
(<= a b c d) ; the sequence a, b, c, d is monotonically non-decreasing
(>= a b c d) ; the sequence a, b, c, d is monotonically non-increasing
Jörg W Mittag
fuente
3

Es simplemente porque los diseñadores de idiomas no lo pensaron o no pensaron que fuera una buena idea. Python lo hace como lo describiste con una gramática LL (1) simple (casi).

Neil G
fuente
1
Esto aún se analizará con una gramática normal en casi cualquier lenguaje convencional; simplemente no se entenderá correctamente por la razón que dio @RobertHarvey.
Mason Wheeler
@MasonWheeler No, no necesariamente. Si las reglas se escriben de modo que las comparaciones sean intercambiables con otros operadores (por ejemplo, porque tienen la misma precedencia), no obtendrá el comportamiento correcto. El hecho de que Python esté poniendo todas las comparaciones en un nivel es lo que le permite tratar la secuencia como una conjunción.
Neil G
1
Realmente no. Poner 1 < 2 < 3en Java o C # y no tiene un problema con la precedencia del operador; Tiene un problema con los tipos no válidos. El problema es que esto seguirá analizándose exactamente como lo escribió, pero necesita una lógica de casos especiales en el compilador para pasar de una secuencia de comparaciones individuales a una comparación encadenada.
Mason Wheeler
2
@MasonWheeler Lo que digo es que el lenguaje tiene que estar diseñado para que funcione. Una parte de eso es acertar con la gramática. (Si las reglas se escriben de modo que las comparaciones sean intercambiables con otros operadores, por ejemplo, porque tienen la misma precedencia, entonces no obtendrá el comportamiento correcto). Otra parte de eso es interpretar el AST como una conjunción, que C ++ no lo hace El punto principal de mi respuesta es que es la decisión de un diseñador de idiomas.
Neil G
@MasonWheeler Creo que estamos de acuerdo. Solo estaba destacando que no es difícil obtener la gramática correcta para esto. Es solo una cuestión de decidir de antemano que desea que funcione de esta manera.
Neil G
2

El siguiente programa de C ++ compila con un pío de clang, incluso con advertencias configuradas al nivel más alto posible ( -Weverything):

#include <iostream>
int main () { std::cout << (1 < 3 < 2) << '\n'; }

El conjunto de compiladores de GNU, por otro lado, me advierte muy bien comparisons like 'X<=Y<=Z' do not have their mathematical meaning [-Wparentheses].

Entonces, mi pregunta es esta: ¿por qué x <y <z no está comúnmente disponible en lenguajes de programación, con la semántica esperada?

La respuesta es simple: compatibilidad con versiones anteriores. Hay una gran cantidad de código en la naturaleza que utiliza el equivalente de1<3<2 y espera que el resultado sea verdadero.

Un diseñador de idiomas solo tiene una oportunidad de hacer esto "correcto", y ese es el momento en que el idioma se diseña por primera vez. Obtener "incorrecto" inicialmente significa que otros programadores se aprovecharán rápidamente de ese comportamiento "incorrecto". Hacerlo "correcto" la segunda vez romperá esa base de código existente.

David Hammen
fuente
+1 porque este programa genera '1' como resultado de una expresión que es obviamente falsa en matemáticas. Aunque está ideado, un ejemplo del mundo real con nombres de variables incomprensibles se convertiría en una pesadilla de depuración si se agrega esta función de lenguaje.
Seth Battin
@SethBattin: esta no es una pesadilla de depuración en Python. El único problema en Python es if x == y is True : ..., en mi opinión: las personas que escriben ese tipo de código merecen ser sometidas a algún tipo de tortura extraordinariamente especial que (si estuviera vivo ahora) haría que el propio Torquemada se desmayara.
David Hammen